diff options
| author | Alfredo Sumaran <alfredo@gitlab.com> | 2017-03-13 21:53:18 +0000 | 
|---|---|---|
| committer | Alfredo Sumaran <alfredo@gitlab.com> | 2017-03-13 21:53:18 +0000 | 
| commit | 302d0453113dd053d23622f857ecdede1e94f717 (patch) | |
| tree | c33a7e85bcee565159a7f25c252b909ebf6b6504 | |
| parent | 18a688ffdaab6f3908bb7620a226ff770b7ee7ba (diff) | |
| parent | c8f986fe115d19c3f6ec014e20c7399918914d10 (diff) | |
| download | gitlab-ce-302d0453113dd053d23622f857ecdede1e94f717.tar.gz | |
Merge branch 'remove-iifes-1' into 'master'
29399-add-documentation-workflow-to-ci
Remove IIFEs for several JS files - Part 1
See merge request !9884
35 files changed, 3683 insertions, 3748 deletions
| diff --git a/app/assets/javascripts/abuse_reports.js b/app/assets/javascripts/abuse_reports.js index 8a260aae1b1..346de4ad11e 100644 --- a/app/assets/javascripts/abuse_reports.js +++ b/app/assets/javascripts/abuse_reports.js @@ -1,40 +1,37 @@ -/* eslint-disable no-param-reassign */ +const MAX_MESSAGE_LENGTH = 500; +const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; -((global) => { -  const MAX_MESSAGE_LENGTH = 500; -  const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; - -  class AbuseReports { -    constructor() { -      $(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage); -      $(document) -        .off('click', MESSAGE_CELL_SELECTOR) -        .on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation); -    } +class AbuseReports { +  constructor() { +    $(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage); +    $(document) +      .off('click', MESSAGE_CELL_SELECTOR) +      .on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation); +  } -    truncateLongMessage() { -      const $messageCellElement = $(this); -      const reportMessage = $messageCellElement.text(); -      if (reportMessage.length > MAX_MESSAGE_LENGTH) { -        $messageCellElement.data('original-message', reportMessage); -        $messageCellElement.data('message-truncated', 'true'); -        $messageCellElement.text(global.text.truncate(reportMessage, MAX_MESSAGE_LENGTH)); -      } +  truncateLongMessage() { +    const $messageCellElement = $(this); +    const reportMessage = $messageCellElement.text(); +    if (reportMessage.length > MAX_MESSAGE_LENGTH) { +      $messageCellElement.data('original-message', reportMessage); +      $messageCellElement.data('message-truncated', 'true'); +      $messageCellElement.text(window.gl.text.truncate(reportMessage, MAX_MESSAGE_LENGTH));      } +  } -    toggleMessageTruncation() { -      const $messageCellElement = $(this); -      const originalMessage = $messageCellElement.data('original-message'); -      if (!originalMessage) return; -      if ($messageCellElement.data('message-truncated') === 'true') { -        $messageCellElement.data('message-truncated', 'false'); -        $messageCellElement.text(originalMessage); -      } else { -        $messageCellElement.data('message-truncated', 'true'); -        $messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`); -      } +  toggleMessageTruncation() { +    const $messageCellElement = $(this); +    const originalMessage = $messageCellElement.data('original-message'); +    if (!originalMessage) return; +    if ($messageCellElement.data('message-truncated') === 'true') { +      $messageCellElement.data('message-truncated', 'false'); +      $messageCellElement.text(originalMessage); +    } else { +      $messageCellElement.data('message-truncated', 'true'); +      $messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`);      }    } +} -  global.AbuseReports = AbuseReports; -})(window.gl || (window.gl = {})); +window.gl = window.gl || {}; +window.gl.AbuseReports = AbuseReports; diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js index 648cb4d5d85..aebda7780e1 100644 --- a/app/assets/javascripts/activities.js +++ b/app/assets/javascripts/activities.js @@ -2,36 +2,35 @@  /* global Pager */  /* global Cookies */ -((global) => { -  class Activities { -    constructor() { -      Pager.init(20, true, false, this.updateTooltips); -      $('.event-filter-link').on('click', (e) => { -        e.preventDefault(); -        this.toggleFilter(e.currentTarget); -        this.reloadActivities(); -      }); -    } +class Activities { +  constructor() { +    Pager.init(20, true, false, this.updateTooltips); +    $('.event-filter-link').on('click', (e) => { +      e.preventDefault(); +      this.toggleFilter(e.currentTarget); +      this.reloadActivities(); +    }); +  } -    updateTooltips() { -      gl.utils.localTimeAgo($('.js-timeago', '.content_list')); -    } +  updateTooltips() { +    gl.utils.localTimeAgo($('.js-timeago', '.content_list')); +  } -    reloadActivities() { -      $('.content_list').html(''); -      Pager.init(20, true, false, this.updateTooltips); -    } +  reloadActivities() { +    $('.content_list').html(''); +    Pager.init(20, true, false, this.updateTooltips); +  } -    toggleFilter(sender) { -      const $sender = $(sender); -      const filter = $sender.attr('id').split('_')[0]; +  toggleFilter(sender) { +    const $sender = $(sender); +    const filter = $sender.attr('id').split('_')[0]; -      $('.event-filter .active').removeClass('active'); -      Cookies.set('event_filter', filter); +    $('.event-filter .active').removeClass('active'); +    Cookies.set('event_filter', filter); -      $sender.closest('li').toggleClass('active'); -    } +    $sender.closest('li').toggleClass('active');    } +} -  global.Activities = Activities; -})(window.gl || (window.gl = {})); +window.gl = window.gl || {}; +window.gl.Activities = Activities; diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index aaed74d6073..34669dd13d6 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -1,64 +1,62 @@  /* 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 */ -(function() { -  this.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(); -    } +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(); +  } -    return Admin; -  })(); -}).call(window); +  return Admin; +})(); diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 86e0ad89431..a0946eb392a 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -1,150 +1,148 @@  /* eslint-disable func-names, space-before-function-paren, quotes, object-shorthand, camelcase, no-var, comma-dangle, prefer-arrow-callback, quote-props, no-param-reassign, max-len */ -(function() { -  var Api = { -    groupsPath: "/api/:version/groups.json", -    groupPath: "/api/:version/groups/:id.json", -    namespacesPath: "/api/:version/namespaces.json", -    groupProjectsPath: "/api/:version/groups/:id/projects.json", -    projectsPath: "/api/:version/projects.json?simple=true", -    labelsPath: "/:namespace_path/:project_path/labels", -    licensePath: "/api/:version/templates/licenses/:key", -    gitignorePath: "/api/:version/templates/gitignores/:key", -    gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", -    dockerfilePath: "/api/:version/templates/dockerfiles/:key", -    issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", -    group: function(group_id, callback) { -      var url = Api.buildUrl(Api.groupPath) -        .replace(':id', group_id); -      return $.ajax({ -        url: url, -        dataType: "json" -      }).done(function(group) { -        return callback(group); -      }); -    }, -    // Return groups list. Filtered by query -    groups: function(query, options, callback) { -      var url = Api.buildUrl(Api.groupsPath); -      return $.ajax({ -        url: url, -        data: $.extend({ -          search: query, -          per_page: 20 -        }, options), -        dataType: "json" -      }).done(function(groups) { -        return callback(groups); -      }); -    }, -    // Return namespaces list. Filtered by query -    namespaces: function(query, callback) { -      var url = Api.buildUrl(Api.namespacesPath); -      return $.ajax({ -        url: url, -        data: { -          search: query, -          per_page: 20 -        }, -        dataType: "json" -      }).done(function(namespaces) { -        return callback(namespaces); -      }); -    }, -    // Return projects list. Filtered by query -    projects: function(query, order, callback) { -      var url = Api.buildUrl(Api.projectsPath); -      return $.ajax({ -        url: url, -        data: { -          search: query, -          order_by: order, -          per_page: 20 -        }, -        dataType: "json" -      }).done(function(projects) { -        return callback(projects); -      }); -    }, -    newLabel: function(namespace_path, project_path, data, callback) { -      var url = Api.buildUrl(Api.labelsPath) -        .replace(':namespace_path', namespace_path) -        .replace(':project_path', project_path); -      return $.ajax({ -        url: url, -        type: "POST", -        data: { 'label': data }, -        dataType: "json" -      }).done(function(label) { -        return callback(label); -      }).error(function(message) { -        return callback(message.responseJSON); -      }); -    }, -    // Return group projects list. Filtered by query -    groupProjects: function(group_id, query, callback) { -      var url = Api.buildUrl(Api.groupProjectsPath) -        .replace(':id', group_id); -      return $.ajax({ -        url: url, -        data: { -          search: query, -          per_page: 20 -        }, -        dataType: "json" -      }).done(function(projects) { -        return callback(projects); -      }); -    }, -    // Return text for a specific license -    licenseText: function(key, data, callback) { -      var url = Api.buildUrl(Api.licensePath) -        .replace(':key', key); -      return $.ajax({ -        url: url, -        data: data -      }).done(function(license) { -        return callback(license); -      }); -    }, -    gitignoreText: function(key, callback) { -      var url = Api.buildUrl(Api.gitignorePath) -        .replace(':key', key); -      return $.get(url, function(gitignore) { -        return callback(gitignore); -      }); -    }, -    gitlabCiYml: function(key, callback) { -      var url = Api.buildUrl(Api.gitlabCiYmlPath) -        .replace(':key', key); -      return $.get(url, function(file) { -        return callback(file); -      }); -    }, -    dockerfileYml: function(key, callback) { -      var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key); -      $.get(url, callback); -    }, -    issueTemplate: function(namespacePath, projectPath, key, type, callback) { -      var url = Api.buildUrl(Api.issuableTemplatePath) -        .replace(':key', key) -        .replace(':type', type) -        .replace(':project_path', projectPath) -        .replace(':namespace_path', namespacePath); -      $.ajax({ -        url: url, -        dataType: 'json' -      }).done(function(file) { -        callback(null, file); -      }).error(callback); -    }, -    buildUrl: function(url) { -      if (gon.relative_url_root != null) { -        url = gon.relative_url_root + url; -      } -      return url.replace(':version', gon.api_version); +var Api = { +  groupsPath: "/api/:version/groups.json", +  groupPath: "/api/:version/groups/:id.json", +  namespacesPath: "/api/:version/namespaces.json", +  groupProjectsPath: "/api/:version/groups/:id/projects.json", +  projectsPath: "/api/:version/projects.json?simple=true", +  labelsPath: "/:namespace_path/:project_path/labels", +  licensePath: "/api/:version/templates/licenses/:key", +  gitignorePath: "/api/:version/templates/gitignores/:key", +  gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", +  dockerfilePath: "/api/:version/templates/dockerfiles/:key", +  issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", +  group: function(group_id, callback) { +    var url = Api.buildUrl(Api.groupPath) +      .replace(':id', group_id); +    return $.ajax({ +      url: url, +      dataType: "json" +    }).done(function(group) { +      return callback(group); +    }); +  }, +  // Return groups list. Filtered by query +  groups: function(query, options, callback) { +    var url = Api.buildUrl(Api.groupsPath); +    return $.ajax({ +      url: url, +      data: $.extend({ +        search: query, +        per_page: 20 +      }, options), +      dataType: "json" +    }).done(function(groups) { +      return callback(groups); +    }); +  }, +  // Return namespaces list. Filtered by query +  namespaces: function(query, callback) { +    var url = Api.buildUrl(Api.namespacesPath); +    return $.ajax({ +      url: url, +      data: { +        search: query, +        per_page: 20 +      }, +      dataType: "json" +    }).done(function(namespaces) { +      return callback(namespaces); +    }); +  }, +  // Return projects list. Filtered by query +  projects: function(query, order, callback) { +    var url = Api.buildUrl(Api.projectsPath); +    return $.ajax({ +      url: url, +      data: { +        search: query, +        order_by: order, +        per_page: 20 +      }, +      dataType: "json" +    }).done(function(projects) { +      return callback(projects); +    }); +  }, +  newLabel: function(namespace_path, project_path, data, callback) { +    var url = Api.buildUrl(Api.labelsPath) +      .replace(':namespace_path', namespace_path) +      .replace(':project_path', project_path); +    return $.ajax({ +      url: url, +      type: "POST", +      data: { 'label': data }, +      dataType: "json" +    }).done(function(label) { +      return callback(label); +    }).error(function(message) { +      return callback(message.responseJSON); +    }); +  }, +  // Return group projects list. Filtered by query +  groupProjects: function(group_id, query, callback) { +    var url = Api.buildUrl(Api.groupProjectsPath) +      .replace(':id', group_id); +    return $.ajax({ +      url: url, +      data: { +        search: query, +        per_page: 20 +      }, +      dataType: "json" +    }).done(function(projects) { +      return callback(projects); +    }); +  }, +  // Return text for a specific license +  licenseText: function(key, data, callback) { +    var url = Api.buildUrl(Api.licensePath) +      .replace(':key', key); +    return $.ajax({ +      url: url, +      data: data +    }).done(function(license) { +      return callback(license); +    }); +  }, +  gitignoreText: function(key, callback) { +    var url = Api.buildUrl(Api.gitignorePath) +      .replace(':key', key); +    return $.get(url, function(gitignore) { +      return callback(gitignore); +    }); +  }, +  gitlabCiYml: function(key, callback) { +    var url = Api.buildUrl(Api.gitlabCiYmlPath) +      .replace(':key', key); +    return $.get(url, function(file) { +      return callback(file); +    }); +  }, +  dockerfileYml: function(key, callback) { +    var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key); +    $.get(url, callback); +  }, +  issueTemplate: function(namespacePath, projectPath, key, type, callback) { +    var url = Api.buildUrl(Api.issuableTemplatePath) +      .replace(':key', key) +      .replace(':type', type) +      .replace(':project_path', projectPath) +      .replace(':namespace_path', namespacePath); +    $.ajax({ +      url: url, +      dataType: 'json' +    }).done(function(file) { +      callback(null, file); +    }).error(callback); +  }, +  buildUrl: function(url) { +    if (gon.relative_url_root != null) { +      url = gon.relative_url_root + url;      } -  }; +    return url.replace(':version', gon.api_version); +  } +}; -  window.Api = Api; -}).call(window); +window.Api = Api; diff --git a/app/assets/javascripts/aside.js b/app/assets/javascripts/aside.js index 448e6e2cc78..88756884d16 100644 --- a/app/assets/javascripts/aside.js +++ b/app/assets/javascripts/aside.js @@ -1,25 +1,24 @@  /* 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 */ -(function() { -  this.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'); -        } -      }); -    } -    return Aside; -  })(); -}).call(window); +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'); +      } +    }); +  } + +  return Aside; +})(); diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js index e55405135fb..8630b18a73f 100644 --- a/app/assets/javascripts/autosave.js +++ b/app/assets/javascripts/autosave.js @@ -1,62 +1,61 @@  /* 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 */ -(function() { -  this.Autosave = (function() { -    function Autosave(field, key) { -      this.field = field; -      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)); -    } -    Autosave.prototype.restore = function() { -      var e, text; -      if (window.localStorage == null) { -        return; -      } -      try { -        text = window.localStorage.getItem(this.key); -      } catch (error) { -        e = error; -        return; -      } -      if ((text != null ? text.length : void 0) > 0) { -        this.field.val(text); -      } -      return this.field.trigger("input"); -    }; +window.Autosave = (function() { +  function Autosave(field, key) { +    this.field = field; +    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)); +  } -    Autosave.prototype.save = function() { -      var text; -      if (window.localStorage == null) { -        return; -      } -      text = this.field.val(); -      if ((text != null ? text.length : void 0) > 0) { -        try { -          return window.localStorage.setItem(this.key, text); -        } catch (error) {} -      } else { -        return this.reset(); -      } -    }; +  Autosave.prototype.restore = function() { +    var e, text; +    if (window.localStorage == null) { +      return; +    } +    try { +      text = window.localStorage.getItem(this.key); +    } catch (error) { +      e = error; +      return; +    } +    if ((text != null ? text.length : void 0) > 0) { +      this.field.val(text); +    } +    return this.field.trigger("input"); +  }; -    Autosave.prototype.reset = function() { -      if (window.localStorage == null) { -        return; -      } +  Autosave.prototype.save = function() { +    var text; +    if (window.localStorage == null) { +      return; +    } +    text = this.field.val(); +    if ((text != null ? text.length : void 0) > 0) {        try { -        return window.localStorage.removeItem(this.key); +        return window.localStorage.setItem(this.key, text);        } catch (error) {} -    }; +    } else { +      return this.reset(); +    } +  }; + +  Autosave.prototype.reset = function() { +    if (window.localStorage == null) { +      return; +    } +    try { +      return window.localStorage.removeItem(this.key); +    } catch (error) {} +  }; -    return Autosave; -  })(); -}).call(window); +  return Autosave; +})(); diff --git a/app/assets/javascripts/breakpoints.js b/app/assets/javascripts/breakpoints.js index 22e93328548..2c1f988d987 100644 --- a/app/assets/javascripts/breakpoints.js +++ b/app/assets/javascripts/breakpoints.js @@ -1,72 +1,66 @@  /* 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 */ -(function() { -  var Breakpoints = (function() { -    var BreakpointInstance, instance; +var Breakpoints = (function() { +  var BreakpointInstance, instance; -    function Breakpoints() {} +  function Breakpoints() {} -    instance = null; +  instance = null; -    BreakpointInstance = (function() { -      var BREAKPOINTS; +  BreakpointInstance = (function() { +    var BREAKPOINTS; -      BREAKPOINTS = ["xs", "sm", "md", "lg"]; +    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('')); -      }; +    function BreakpointInstance() { +      this.setup(); +    } -      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]; -      }; +    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('')); +    }; -      return BreakpointInstance; -    })(); +    BreakpointInstance.prototype.visibleDevice = function() { +      var allDeviceSelector; +      allDeviceSelector = BREAKPOINTS.map(function(breakpoint) { +        return ".device-" + breakpoint; +      }); +      return $(allDeviceSelector.join(",")).filter(":visible"); +    }; -    Breakpoints.get = function() { -      return instance != null ? instance : instance = new BreakpointInstance; +    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 Breakpoints; +    return BreakpointInstance;    })(); -  $((function(_this) { -    return function() { -      return _this.bp = Breakpoints.get(); -    }; -  })(this)); +  Breakpoints.get = function() { +    return instance != null ? instance : instance = new BreakpointInstance; +  }; + +  return Breakpoints; +})(); + +$(() => { window.bp = Breakpoints.get(); }); -  window.Breakpoints = Breakpoints; -}).call(window); +window.Breakpoints = Breakpoints; diff --git a/app/assets/javascripts/broadcast_message.js b/app/assets/javascripts/broadcast_message.js index e8531c43b4b..f73e489e7b2 100644 --- a/app/assets/javascripts/broadcast_message.js +++ b/app/assets/javascripts/broadcast_message.js @@ -1,34 +1,33 @@  /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, no-else-return, object-shorthand, comma-dangle, max-len */ -(function() { -  $(function() { -    var previewPath; -    $('input#broadcast_message_color').on('input', function() { -      var previewColor; -      previewColor = $(this).val(); -      return $('div.broadcast-message-preview').css('background-color', previewColor); -    }); -    $('input#broadcast_message_font').on('input', function() { -      var previewColor; -      previewColor = $(this).val(); -      return $('div.broadcast-message-preview').css('color', previewColor); -    }); -    previewPath = $('textarea#broadcast_message_message').data('preview-path'); -    return $('textarea#broadcast_message_message').on('input', function() { -      var message; -      message = $(this).val(); -      if (message === '') { -        return $('.js-broadcast-message-preview').text("Your message here"); -      } else { -        return $.ajax({ -          url: previewPath, -          type: "POST", -          data: { -            broadcast_message: { -              message: message -            } + +$(function() { +  var previewPath; +  $('input#broadcast_message_color').on('input', function() { +    var previewColor; +    previewColor = $(this).val(); +    return $('div.broadcast-message-preview').css('background-color', previewColor); +  }); +  $('input#broadcast_message_font').on('input', function() { +    var previewColor; +    previewColor = $(this).val(); +    return $('div.broadcast-message-preview').css('color', previewColor); +  }); +  previewPath = $('textarea#broadcast_message_message').data('preview-path'); +  return $('textarea#broadcast_message_message').on('input', function() { +    var message; +    message = $(this).val(); +    if (message === '') { +      return $('.js-broadcast-message-preview').text("Your message here"); +    } else { +      return $.ajax({ +        url: previewPath, +        type: "POST", +        data: { +          broadcast_message: { +            message: message            } -        }); -      } -    }); +        } +      }); +    }    }); -}).call(window); +}); diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 6e6e9b18686..6efd26ccc37 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -1,285 +1,283 @@  /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */  /* global Breakpoints */ -(function() { -  var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; -  var AUTO_SCROLL_OFFSET = 75; -  var DOWN_BUILD_TRACE = '#down-build-trace'; - -  this.Build = (function() { -    Build.timeout = null; - -    Build.state = null; - -    function Build(options) { -      options = options || $('.js-build-options').data(); -      this.pageUrl = options.pageUrl; -      this.buildUrl = options.buildUrl; -      this.buildStatus = options.buildStatus; -      this.state = options.logState; -      this.buildStage = options.buildStage; -      this.updateDropdown = bind(this.updateDropdown, this); -      this.$document = $(document); -      this.$body = $('body'); -      this.$buildTrace = $('#build-trace'); -      this.$autoScrollContainer = $('.autoscroll-container'); -      this.$autoScrollStatus = $('#autoscroll-status'); -      this.$autoScrollStatusText = this.$autoScrollStatus.find('.status-text'); -      this.$upBuildTrace = $('#up-build-trace'); -      this.$downBuildTrace = $(DOWN_BUILD_TRACE); -      this.$scrollTopBtn = $('#scroll-top'); -      this.$scrollBottomBtn = $('#scroll-bottom'); -      this.$buildRefreshAnimation = $('.js-build-refresh'); - -      clearTimeout(Build.timeout); -      // Init breakpoint checker -      this.bp = Breakpoints.get(); - -      this.initSidebar(); -      this.$buildScroll = $('#js-build-scroll'); - -      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); -      this.$document.on('scroll', this.initScrollMonitor.bind(this)); -      $(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this)); -      $('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace); -      this.updateArtifactRemoveDate(); -      if ($('#build-trace').length) { -        this.getInitialBuildTrace(); -        this.initScrollButtonAffix(); -      } -      this.invokeBuildTrace(); +var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +var AUTO_SCROLL_OFFSET = 75; +var DOWN_BUILD_TRACE = '#down-build-trace'; + +window.Build = (function() { +  Build.timeout = null; + +  Build.state = null; + +  function Build(options) { +    options = options || $('.js-build-options').data(); +    this.pageUrl = options.pageUrl; +    this.buildUrl = options.buildUrl; +    this.buildStatus = options.buildStatus; +    this.state = options.logState; +    this.buildStage = options.buildStage; +    this.updateDropdown = bind(this.updateDropdown, this); +    this.$document = $(document); +    this.$body = $('body'); +    this.$buildTrace = $('#build-trace'); +    this.$autoScrollContainer = $('.autoscroll-container'); +    this.$autoScrollStatus = $('#autoscroll-status'); +    this.$autoScrollStatusText = this.$autoScrollStatus.find('.status-text'); +    this.$upBuildTrace = $('#up-build-trace'); +    this.$downBuildTrace = $(DOWN_BUILD_TRACE); +    this.$scrollTopBtn = $('#scroll-top'); +    this.$scrollBottomBtn = $('#scroll-bottom'); +    this.$buildRefreshAnimation = $('.js-build-refresh'); + +    clearTimeout(Build.timeout); +    // Init breakpoint checker +    this.bp = Breakpoints.get(); + +    this.initSidebar(); +    this.$buildScroll = $('#js-build-scroll'); + +    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); +    this.$document.on('scroll', this.initScrollMonitor.bind(this)); +    $(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this)); +    $('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace); +    this.updateArtifactRemoveDate(); +    if ($('#build-trace').length) { +      this.getInitialBuildTrace(); +      this.initScrollButtonAffix();      } - -    Build.prototype.initSidebar = function() { -      this.$sidebar = $('.js-build-sidebar'); -      this.$sidebar.niceScroll(); -      this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar); -    }; - -    Build.prototype.location = function() { -      return window.location.href.split("#")[0]; -    }; - -    Build.prototype.invokeBuildTrace = function() { -      var continueRefreshStatuses = ['running', 'pending']; -      // Continue to update build trace when build is running or pending -      if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) { -        // Check for new build output if user still watching build page -        // Only valid for runnig build when output changes during time -        Build.timeout = setTimeout((function(_this) { -          return function() { -            if (_this.location() === _this.pageUrl) { -              return _this.getBuildTrace(); -            } -          }; -        })(this), 4000); -      } -    }; - -    Build.prototype.getInitialBuildTrace = function() { -      var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped']; - -      return $.ajax({ -        url: this.buildUrl, -        dataType: 'json', -        success: function(buildData) { -          $('.js-build-output').html(buildData.trace_html); -          if (window.location.hash === DOWN_BUILD_TRACE) { -            $("html,body").scrollTop(this.$buildTrace.height()); +    this.invokeBuildTrace(); +  } + +  Build.prototype.initSidebar = function() { +    this.$sidebar = $('.js-build-sidebar'); +    this.$sidebar.niceScroll(); +    this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar); +  }; + +  Build.prototype.location = function() { +    return window.location.href.split("#")[0]; +  }; + +  Build.prototype.invokeBuildTrace = function() { +    var continueRefreshStatuses = ['running', 'pending']; +    // Continue to update build trace when build is running or pending +    if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) { +      // Check for new build output if user still watching build page +      // Only valid for runnig build when output changes during time +      Build.timeout = setTimeout((function(_this) { +        return function() { +          if (_this.location() === _this.pageUrl) { +            return _this.getBuildTrace();            } -          if (removeRefreshStatuses.indexOf(buildData.status) !== -1) { -            this.$buildRefreshAnimation.remove(); -            return this.initScrollMonitor(); +        }; +      })(this), 4000); +    } +  }; + +  Build.prototype.getInitialBuildTrace = function() { +    var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped']; + +    return $.ajax({ +      url: this.buildUrl, +      dataType: 'json', +      success: function(buildData) { +        $('.js-build-output').html(buildData.trace_html); +        if (window.location.hash === DOWN_BUILD_TRACE) { +          $("html,body").scrollTop(this.$buildTrace.height()); +        } +        if (removeRefreshStatuses.indexOf(buildData.status) !== -1) { +          this.$buildRefreshAnimation.remove(); +          return this.initScrollMonitor(); +        } +      }.bind(this) +    }); +  }; + +  Build.prototype.getBuildTrace = function() { +    return $.ajax({ +      url: this.pageUrl + "/trace.json?state=" + (encodeURIComponent(this.state)), +      dataType: "json", +      success: (function(_this) { +        return function(log) { +          var pageUrl; + +          if (log.state) { +            _this.state = log.state;            } -        }.bind(this) -      }); -    }; - -    Build.prototype.getBuildTrace = function() { -      return $.ajax({ -        url: this.pageUrl + "/trace.json?state=" + (encodeURIComponent(this.state)), -        dataType: "json", -        success: (function(_this) { -          return function(log) { -            var pageUrl; - -            if (log.state) { -              _this.state = log.state; +          _this.invokeBuildTrace(); +          if (log.status === "running") { +            if (log.append) { +              $('.js-build-output').append(log.html); +            } else { +              $('.js-build-output').html(log.html);              } -            _this.invokeBuildTrace(); -            if (log.status === "running") { -              if (log.append) { -                $('.js-build-output').append(log.html); -              } else { -                $('.js-build-output').html(log.html); -              } -              return _this.checkAutoscroll(); -            } else if (log.status !== _this.buildStatus) { -              pageUrl = _this.pageUrl; -              if (_this.$autoScrollStatus.data('state') === 'enabled') { -                pageUrl += DOWN_BUILD_TRACE; -              } - -              return gl.utils.visitUrl(pageUrl); +            return _this.checkAutoscroll(); +          } else if (log.status !== _this.buildStatus) { +            pageUrl = _this.pageUrl; +            if (_this.$autoScrollStatus.data('state') === 'enabled') { +              pageUrl += DOWN_BUILD_TRACE;              } -          }; -        })(this) -      }); -    }; - -    Build.prototype.checkAutoscroll = function() { -      if (this.$autoScrollStatus.data("state") === "enabled") { -        return $("html,body").scrollTop(this.$buildTrace.height()); -      } - -      // Handle a situation where user started new build -      // but never scrolled a page -      if (!this.$scrollTopBtn.is(':visible') && -          !this.$scrollBottomBtn.is(':visible') && -          !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { -        this.$scrollBottomBtn.show(); -      } -    }; -    Build.prototype.initScrollButtonAffix = function() { -      // Hide everything initially -      this.$scrollTopBtn.hide(); -      this.$scrollBottomBtn.hide(); -      this.$autoScrollContainer.hide(); -    }; - -    // Page scroll listener to detect if user has scrolling page -    // and handle following cases -    // 1) User is at Top of Build Log; -    //      - Hide Top Arrow button -    //      - Show Bottom Arrow button -    //      - Disable Autoscroll and hide indicator (when build is running) -    // 2) User is at Bottom of Build Log; -    //      - Show Top Arrow button -    //      - Hide Bottom Arrow button -    //      - Enable Autoscroll and show indicator (when build is running) -    // 3) User is somewhere in middle of Build Log; -    //      - Show Top Arrow button -    //      - Show Bottom Arrow button -    //      - Disable Autoscroll and hide indicator (when build is running) -    Build.prototype.initScrollMonitor = function() { -      if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { -        // User is somewhere in middle of Build Log - -        this.$scrollTopBtn.show(); - -        if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed -          this.$scrollBottomBtn.show(); -        } else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) { -          this.$scrollBottomBtn.show(); -        } else { -          this.$scrollBottomBtn.hide(); -        } - -        // Hide Autoscroll Status Indicator -        if (this.$scrollBottomBtn.is(':visible')) { -          this.$autoScrollContainer.hide(); -          this.$autoScrollStatusText.removeClass('animate'); -        } else { -          this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show(); -          this.$autoScrollStatusText.addClass('animate'); -        } -      } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { -        // User is at Top of Build Log +            return gl.utils.visitUrl(pageUrl); +          } +        }; +      })(this) +    }); +  }; + +  Build.prototype.checkAutoscroll = function() { +    if (this.$autoScrollStatus.data("state") === "enabled") { +      return $("html,body").scrollTop(this.$buildTrace.height()); +    } -        this.$scrollTopBtn.hide(); +    // Handle a situation where user started new build +    // but never scrolled a page +    if (!this.$scrollTopBtn.is(':visible') && +        !this.$scrollBottomBtn.is(':visible') && +        !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { +      this.$scrollBottomBtn.show(); +    } +  }; + +  Build.prototype.initScrollButtonAffix = function() { +    // Hide everything initially +    this.$scrollTopBtn.hide(); +    this.$scrollBottomBtn.hide(); +    this.$autoScrollContainer.hide(); +  }; + +  // Page scroll listener to detect if user has scrolling page +  // and handle following cases +  // 1) User is at Top of Build Log; +  //      - Hide Top Arrow button +  //      - Show Bottom Arrow button +  //      - Disable Autoscroll and hide indicator (when build is running) +  // 2) User is at Bottom of Build Log; +  //      - Show Top Arrow button +  //      - Hide Bottom Arrow button +  //      - Enable Autoscroll and show indicator (when build is running) +  // 3) User is somewhere in middle of Build Log; +  //      - Show Top Arrow button +  //      - Show Bottom Arrow button +  //      - Disable Autoscroll and hide indicator (when build is running) +  Build.prototype.initScrollMonitor = function() { +    if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { +      // User is somewhere in middle of Build Log + +      this.$scrollTopBtn.show(); + +      if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed +        this.$scrollBottomBtn.show(); +      } else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {          this.$scrollBottomBtn.show(); +      } else { +        this.$scrollBottomBtn.hide(); +      } +      // Hide Autoscroll Status Indicator +      if (this.$scrollBottomBtn.is(':visible')) {          this.$autoScrollContainer.hide();          this.$autoScrollStatusText.removeClass('animate'); -      } else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) || -                 (this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) { -        // User is at Bottom of Build Log - -        this.$scrollTopBtn.show(); -        this.$scrollBottomBtn.hide(); - -        // Show and Reposition Autoscroll Status Indicator +      } else {          this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();          this.$autoScrollStatusText.addClass('animate'); -      } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) { -        // Build Log height is small +      } +    } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { +      // User is at Top of Build Log -        this.$scrollTopBtn.hide(); -        this.$scrollBottomBtn.hide(); +      this.$scrollTopBtn.hide(); +      this.$scrollBottomBtn.show(); -        // Hide Autoscroll Status Indicator -        this.$autoScrollContainer.hide(); -        this.$autoScrollStatusText.removeClass('animate'); -      } +      this.$autoScrollContainer.hide(); +      this.$autoScrollStatusText.removeClass('animate'); +    } else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) || +               (this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) { +      // User is at Bottom of Build Log -      if (this.buildStatus === "running" || this.buildStatus === "pending") { -        // Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise. -        this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled'); -      } -    }; - -    Build.prototype.shouldHideSidebarForViewport = function() { -      var bootstrapBreakpoint; -      bootstrapBreakpoint = this.bp.getBreakpointSize(); -      return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; -    }; - -    Build.prototype.toggleSidebar = function(shouldHide) { -      var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; -      this.$buildScroll.toggleClass('sidebar-expanded', shouldShow) -        .toggleClass('sidebar-collapsed', shouldHide); -      this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow) -        .toggleClass('right-sidebar-collapsed', shouldHide); -    }; - -    Build.prototype.sidebarOnResize = function() { -      this.toggleSidebar(this.shouldHideSidebarForViewport()); -    }; - -    Build.prototype.sidebarOnClick = function() { -      if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); -    }; - -    Build.prototype.updateArtifactRemoveDate = function() { -      var $date, date; -      $date = $('.js-artifacts-remove'); -      if ($date.length) { -        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(); -      var stage = e.currentTarget.text; -      this.updateStageDropdownText(stage); -      this.populateJobs(stage); -    }; - -    Build.prototype.stepTrace = function(e) { -      var $currentTarget; -      e.preventDefault(); -      $currentTarget = $(e.currentTarget); -      $.scrollTo($currentTarget.attr('href'), { -        offset: 0 -      }); -    }; - -    return Build; -  })(); -}).call(window); +      this.$scrollTopBtn.show(); +      this.$scrollBottomBtn.hide(); + +      // Show and Reposition Autoscroll Status Indicator +      this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show(); +      this.$autoScrollStatusText.addClass('animate'); +    } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) { +      // Build Log height is small + +      this.$scrollTopBtn.hide(); +      this.$scrollBottomBtn.hide(); + +      // Hide Autoscroll Status Indicator +      this.$autoScrollContainer.hide(); +      this.$autoScrollStatusText.removeClass('animate'); +    } + +    if (this.buildStatus === "running" || this.buildStatus === "pending") { +      // Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise. +      this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled'); +    } +  }; + +  Build.prototype.shouldHideSidebarForViewport = function() { +    var bootstrapBreakpoint; +    bootstrapBreakpoint = this.bp.getBreakpointSize(); +    return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; +  }; + +  Build.prototype.toggleSidebar = function(shouldHide) { +    var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; +    this.$buildScroll.toggleClass('sidebar-expanded', shouldShow) +      .toggleClass('sidebar-collapsed', shouldHide); +    this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow) +      .toggleClass('right-sidebar-collapsed', shouldHide); +  }; + +  Build.prototype.sidebarOnResize = function() { +    this.toggleSidebar(this.shouldHideSidebarForViewport()); +  }; + +  Build.prototype.sidebarOnClick = function() { +    if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); +  }; + +  Build.prototype.updateArtifactRemoveDate = function() { +    var $date, date; +    $date = $('.js-artifacts-remove'); +    if ($date.length) { +      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(); +    var stage = e.currentTarget.text; +    this.updateStageDropdownText(stage); +    this.populateJobs(stage); +  }; + +  Build.prototype.stepTrace = function(e) { +    var $currentTarget; +    e.preventDefault(); +    $currentTarget = $(e.currentTarget); +    $.scrollTo($currentTarget.attr('href'), { +      offset: 0 +    }); +  }; + +  return Build; +})(); diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js index cae9a0ffca4..bd479700fd3 100644 --- a/app/assets/javascripts/build_artifacts.js +++ b/app/assets/javascripts/build_artifacts.js @@ -1,26 +1,25 @@  /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, no-return-assign, max-len */ -(function() { -  this.BuildArtifacts = (function() { -    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(); -      }); -    }; +window.BuildArtifacts = (function() { +  function BuildArtifacts() { +    this.disablePropagation(); +    this.setupEntryClick(); +  } -    BuildArtifacts.prototype.setupEntryClick = function() { -      return $('.tree-holder').on('click', 'tr[data-link]', function(e) { -        return window.location = this.dataset.link; -      }); -    }; +  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(); +    }); +  }; -    return BuildArtifacts; -  })(); -}).call(window); +  BuildArtifacts.prototype.setupEntryClick = function() { +    return $('.tree-holder').on('click', 'tr[data-link]', function(e) { +      return window.location = this.dataset.link; +    }); +  }; + +  return BuildArtifacts; +})(); diff --git a/app/assets/javascripts/ci_lint_editor.js b/app/assets/javascripts/ci_lint_editor.js index 56ffaa765a8..dd4a08a2f31 100644 --- a/app/assets/javascripts/ci_lint_editor.js +++ b/app/assets/javascripts/ci_lint_editor.js @@ -1,18 +1,17 @@ -(() => { -  window.gl = window.gl || {}; -  class CILintEditor { -    constructor() { -      this.editor = window.ace.edit('ci-editor'); -      this.textarea = document.querySelector('#content'); +window.gl = window.gl || {}; -      this.editor.getSession().setMode('ace/mode/yaml'); -      this.editor.on('input', () => { -        const content = this.editor.getSession().getValue(); -        this.textarea.value = content; -      }); -    } +class CILintEditor { +  constructor() { +    this.editor = window.ace.edit('ci-editor'); +    this.textarea = document.querySelector('#content'); + +    this.editor.getSession().setMode('ace/mode/yaml'); +    this.editor.on('input', () => { +      const content = this.editor.getSession().getValue(); +      this.textarea.value = content; +    });    } +} -  gl.CILintEditor = CILintEditor; -})(); +gl.CILintEditor = CILintEditor; diff --git a/app/assets/javascripts/commit.js b/app/assets/javascripts/commit.js index 566b322eb49..5f637524e30 100644 --- a/app/assets/javascripts/commit.js +++ b/app/assets/javascripts/commit.js @@ -1,14 +1,12 @@  /* eslint-disable func-names, space-before-function-paren, wrap-iife */  /* global CommitFile */ -(function() { -  this.Commit = (function() { -    function Commit() { -      $('.files .diff-file').each(function() { -        return new CommitFile(this); -      }); -    } +window.Commit = (function() { +  function Commit() { +    $('.files .diff-file').each(function() { +      return new CommitFile(this); +    }); +  } -    return Commit; -  })(); -}).call(window); +  return Commit; +})(); diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index ccd895f3bf4..e3f9eaaf39c 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -1,68 +1,66 @@  /* 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 */ -(function() { -  this.CommitsList = (function() { -    var CommitsList = {}; +window.CommitsList = (function() { +  var CommitsList = {}; -    CommitsList.timer = null; +  CommitsList.timer = null; -    CommitsList.init = function(limit) { -      $("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, function() { -        gl.utils.localTimeAgo($('.js-timeago')); -      }); -      this.content = $("#commits-list"); -      this.searchField = $("#commits-search"); -      this.lastSearch = this.searchField.val(); -      return this.initSearch(); -    }; +  CommitsList.init = function(limit) { +    $("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, function() { +      gl.utils.localTimeAgo($('.js-timeago')); +    }); +    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((function(_this) { +      return function() { +        clearTimeout(_this.timer); +        return _this.timer = setTimeout(_this.filterResults, 500); +      }; +    })(this)); +  }; -    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" +    }); +  }; -    return CommitsList; -  })(); -}).call(window); +  return CommitsList; +})(); diff --git a/app/assets/javascripts/compare.js b/app/assets/javascripts/compare.js index 15df105d4cc..9e5dbd64a7e 100644 --- a/app/assets/javascripts/compare.js +++ b/app/assets/javascripts/compare.js @@ -1,91 +1,90 @@  /* 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 */ -(function() { -  this.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(); -              } + +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(); -    } +          } +        }); +      }; +    })(this)); +    this.initialState(); +  } -    Compare.prototype.initialState = function() { -      this.getSourceHtml(); -      return this.getTargetHtml(); -    }; +  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() -        }, -        beforeSend: function() { -          return $('.mr_target_commit').empty(); -        }, -        success: function(html) { -          return $('.js-target-branch-dropdown .dropdown-content').html(html); -        } -      }); -    }; +  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.getSourceHtml = function() { -      return this.sendAjax(this.opts.sourceBranchUrl, this.source_loading, '.mr_source_commit', { -        ref: $("input[name='merge_request[source_branch]']").val() -      }); -    }; +  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.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)); -        } -      }); -    }; +  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; -  })(); -}).call(window); +  return Compare; +})(); diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index 1eca973e069..d91bfb1ccbd 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -1,69 +1,67 @@  /* 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 */ -(function() { -  this.CompareAutocomplete = (function() { -    function CompareAutocomplete() { -      this.initDropdown(); -    } +window.CompareAutocomplete = (function() { +  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') -              } -            }).done(function(refs) { -              return callback(refs); -            }); -          }, -          selectable: true, -          filterable: true, -          filterByText: 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')              } -          }, -          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, +        filterByText: 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; -  })(); -}).call(window); +  return CompareAutocomplete; +})(); diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js index a1c1b721228..b375b61202e 100644 --- a/app/assets/javascripts/confirm_danger_modal.js +++ b/app/assets/javascripts/confirm_danger_modal.js @@ -1,31 +1,30 @@  /* 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 */ -(function() { -  this.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)); -    } -    return ConfirmDangerModal; -  })(); -}).call(window); +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)); +  } + +  return ConfirmDangerModal; +})(); diff --git a/app/assets/javascripts/copy_as_gfm.js b/app/assets/javascripts/copy_as_gfm.js index 8883c339335..0fb7bde1fd6 100644 --- a/app/assets/javascripts/copy_as_gfm.js +++ b/app/assets/javascripts/copy_as_gfm.js @@ -1,364 +1,361 @@  /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ -/* jshint esversion: 6 */  require('./lib/utils/common_utils'); -(() => { -  const gfmRules = { -    // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert -    // GitLab Flavored Markdown (GFM) to HTML. -    // These handlers consequently convert that same HTML to GFM to be copied to the clipboard. -    // Every filter in lib/banzai/pipeline/gfm_pipeline.rb that generates HTML -    // from GFM should have a handler here, in reverse order. -    // The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb. -    InlineDiffFilter: { -      'span.idiff.addition'(el, text) { -        return `{+${text}+}`; -      }, -      'span.idiff.deletion'(el, text) { -        return `{-${text}-}`; -      }, -    }, -    TaskListFilter: { -      'input[type=checkbox].task-list-item-checkbox'(el, text) { -        return `[${el.checked ? 'x' : ' '}]`; -      }, -    }, -    ReferenceFilter: { -      '.tooltip'(el, text) { -        return ''; -      }, -      'a.gfm:not([data-link=true])'(el, text) { -        return el.dataset.original || text; -      }, -    }, -    AutolinkFilter: { -      'a'(el, text) { -        // Fallback on the regular MarkdownFilter's `a` handler. -        if (text !== el.getAttribute('href')) return false; - -        return text; -      }, -    }, -    TableOfContentsFilter: { -      'ul.section-nav'(el, text) { -        return '[[_TOC_]]'; -      }, -    }, -    EmojiFilter: { -      'img.emoji'(el, text) { -        return el.getAttribute('alt'); -      }, -      'gl-emoji'(el, text) { -        return `:${el.getAttribute('data-name')}:`; -      }, -    }, -    ImageLinkFilter: { -      'a.no-attachment-icon'(el, text) { -        return text; -      }, -    }, -    VideoLinkFilter: { -      '.video-container'(el, text) { -        const videoEl = el.querySelector('video'); -        if (!videoEl) return false; - -        return CopyAsGFM.nodeToGFM(videoEl); -      }, -      'video'(el, text) { -        return `})`; -      }, -    }, -    MathFilter: { -      'pre.code.math[data-math-style=display]'(el, text) { -        return `\`\`\`math\n${text.trim()}\n\`\`\``; -      }, -      'code.code.math[data-math-style=inline]'(el, text) { -        return `$\`${text}\`$`; -      }, -      'span.katex-display span.katex-mathml'(el, text) { -        const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]'); -        if (!mathAnnotation) return false; - -        return `\`\`\`math\n${CopyAsGFM.nodeToGFM(mathAnnotation)}\n\`\`\``; -      }, -      'span.katex-mathml'(el, text) { -        const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]'); -        if (!mathAnnotation) return false; - -        return `$\`${CopyAsGFM.nodeToGFM(mathAnnotation)}\`$`; -      }, -      'span.katex-html'(el, text) { -        // We don't want to include the content of this element in the copied text. -        return ''; -      }, -      'annotation[encoding="application/x-tex"]'(el, text) { -        return text.trim(); -      }, -    }, -    SanitizationFilter: { -      'a[name]:not([href]):empty'(el, text) { -        return el.outerHTML; -      }, -      'dl'(el, text) { -        let lines = text.trim().split('\n'); -        // Add two spaces to the front of subsequent list items lines, -        // or leave the line entirely blank. -        lines = lines.map((l) => { +const gfmRules = { +  // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert +  // GitLab Flavored Markdown (GFM) to HTML. +  // These handlers consequently convert that same HTML to GFM to be copied to the clipboard. +  // Every filter in lib/banzai/pipeline/gfm_pipeline.rb that generates HTML +  // from GFM should have a handler here, in reverse order. +  // The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb. +  InlineDiffFilter: { +    'span.idiff.addition'(el, text) { +      return `{+${text}+}`; +    }, +    'span.idiff.deletion'(el, text) { +      return `{-${text}-}`; +    }, +  }, +  TaskListFilter: { +    'input[type=checkbox].task-list-item-checkbox'(el, text) { +      return `[${el.checked ? 'x' : ' '}]`; +    }, +  }, +  ReferenceFilter: { +    '.tooltip'(el, text) { +      return ''; +    }, +    'a.gfm:not([data-link=true])'(el, text) { +      return el.dataset.original || text; +    }, +  }, +  AutolinkFilter: { +    'a'(el, text) { +      // Fallback on the regular MarkdownFilter's `a` handler. +      if (text !== el.getAttribute('href')) return false; + +      return text; +    }, +  }, +  TableOfContentsFilter: { +    'ul.section-nav'(el, text) { +      return '[[_TOC_]]'; +    }, +  }, +  EmojiFilter: { +    'img.emoji'(el, text) { +      return el.getAttribute('alt'); +    }, +    'gl-emoji'(el, text) { +      return `:${el.getAttribute('data-name')}:`; +    }, +  }, +  ImageLinkFilter: { +    'a.no-attachment-icon'(el, text) { +      return text; +    }, +  }, +  VideoLinkFilter: { +    '.video-container'(el, text) { +      const videoEl = el.querySelector('video'); +      if (!videoEl) return false; + +      return CopyAsGFM.nodeToGFM(videoEl); +    }, +    'video'(el, text) { +      return `})`; +    }, +  }, +  MathFilter: { +    'pre.code.math[data-math-style=display]'(el, text) { +      return `\`\`\`math\n${text.trim()}\n\`\`\``; +    }, +    'code.code.math[data-math-style=inline]'(el, text) { +      return `$\`${text}\`$`; +    }, +    'span.katex-display span.katex-mathml'(el, text) { +      const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]'); +      if (!mathAnnotation) return false; + +      return `\`\`\`math\n${CopyAsGFM.nodeToGFM(mathAnnotation)}\n\`\`\``; +    }, +    'span.katex-mathml'(el, text) { +      const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]'); +      if (!mathAnnotation) return false; + +      return `$\`${CopyAsGFM.nodeToGFM(mathAnnotation)}\`$`; +    }, +    'span.katex-html'(el, text) { +      // We don't want to include the content of this element in the copied text. +      return ''; +    }, +    'annotation[encoding="application/x-tex"]'(el, text) { +      return text.trim(); +    }, +  }, +  SanitizationFilter: { +    'a[name]:not([href]):empty'(el, text) { +      return el.outerHTML; +    }, +    'dl'(el, text) { +      let lines = text.trim().split('\n'); +      // Add two spaces to the front of subsequent list items lines, +      // or leave the line entirely blank. +      lines = lines.map((l) => { +        const line = l.trim(); +        if (line.length === 0) return ''; + +        return `  ${line}`; +      }); + +      return `<dl>\n${lines.join('\n')}\n</dl>`; +    }, +    'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr, summary, details'(el, text) { +      const tag = el.nodeName.toLowerCase(); +      return `<${tag}>${text}</${tag}>`; +    }, +  }, +  SyntaxHighlightFilter: { +    'pre.code.highlight'(el, t) { +      const text = t.trim(); + +      let lang = el.getAttribute('lang'); +      if (lang === 'plaintext') { +        lang = ''; +      } + +      // Prefixes lines with 4 spaces if the code contains triple backticks +      if (lang === '' && text.match(/^```/gm)) { +        return text.split('\n').map((l) => {            const line = l.trim();            if (line.length === 0) return ''; -          return `  ${line}`; -        }); +          return `    ${line}`; +        }).join('\n'); +      } -        return `<dl>\n${lines.join('\n')}\n</dl>`; -      }, -      'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr, summary, details'(el, text) { -        const tag = el.nodeName.toLowerCase(); -        return `<${tag}>${text}</${tag}>`; -      }, +      return `\`\`\`${lang}\n${text}\n\`\`\``; +    }, +    'pre > code'(el, text) { +       // Don't wrap code blocks in `` +      return text; +    }, +  }, +  MarkdownFilter: { +    'br'(el, text) { +      // Two spaces at the end of a line are turned into a BR +      return '  ';      }, -    SyntaxHighlightFilter: { -      'pre.code.highlight'(el, t) { -        const text = t.trim(); +    'code'(el, text) { +      let backtickCount = 1; +      const backtickMatch = text.match(/`+/); +      if (backtickMatch) { +        backtickCount = backtickMatch[0].length + 1; +      } -        let lang = el.getAttribute('lang'); -        if (lang === 'plaintext') { -          lang = ''; -        } +      const backticks = Array(backtickCount + 1).join('`'); +      const spaceOrNoSpace = backtickCount > 1 ? ' ' : ''; -        // Prefixes lines with 4 spaces if the code contains triple backticks -        if (lang === '' && text.match(/^```/gm)) { -          return text.split('\n').map((l) => { -            const line = l.trim(); -            if (line.length === 0) return ''; +      return backticks + spaceOrNoSpace + text + spaceOrNoSpace + backticks; +    }, +    'blockquote'(el, text) { +      return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n'); +    }, +    'img'(el, text) { +      return `})`; +    }, +    'a.anchor'(el, text) { +      // Don't render a Markdown link for the anchor link inside a heading +      return text; +    }, +    'a'(el, text) { +      return `[${text}](${el.getAttribute('href')})`; +    }, +    'li'(el, text) { +      const lines = text.trim().split('\n'); +      const firstLine = `- ${lines.shift()}`; +      // Add four spaces to the front of subsequent list items lines, +      // or leave the line entirely blank. +      const nextLines = lines.map((s) => { +        if (s.trim().length === 0) return ''; + +        return `    ${s}`; +      }); + +      return `${firstLine}\n${nextLines.join('\n')}`; +    }, +    'ul'(el, text) { +      return text; +    }, +    'ol'(el, text) { +      // LIs get a `- ` prefix by default, which we replace by `1. ` for ordered lists. +      return text.replace(/^- /mg, '1. '); +    }, +    'h1'(el, text) { +      return `# ${text.trim()}`; +    }, +    'h2'(el, text) { +      return `## ${text.trim()}`; +    }, +    'h3'(el, text) { +      return `### ${text.trim()}`; +    }, +    'h4'(el, text) { +      return `#### ${text.trim()}`; +    }, +    'h5'(el, text) { +      return `##### ${text.trim()}`; +    }, +    'h6'(el, text) { +      return `###### ${text.trim()}`; +    }, +    'strong'(el, text) { +      return `**${text}**`; +    }, +    'em'(el, text) { +      return `_${text}_`; +    }, +    'del'(el, text) { +      return `~~${text}~~`; +    }, +    'sup'(el, text) { +      return `^${text}`; +    }, +    'hr'(el, text) { +      return '-----'; +    }, +    'table'(el, text) { +      const theadEl = el.querySelector('thead'); +      const tbodyEl = el.querySelector('tbody'); +      if (!theadEl || !tbodyEl) return false; -            return `    ${line}`; -          }).join('\n'); -        } +      const theadText = CopyAsGFM.nodeToGFM(theadEl); +      const tbodyText = CopyAsGFM.nodeToGFM(tbodyEl); -        return `\`\`\`${lang}\n${text}\n\`\`\``; -      }, -      'pre > code'(el, text) { -         // Don't wrap code blocks in `` -        return text; -      }, -    }, -    MarkdownFilter: { -      'br'(el, text) { -        // Two spaces at the end of a line are turned into a BR -        return '  '; -      }, -      'code'(el, text) { -        let backtickCount = 1; -        const backtickMatch = text.match(/`+/); -        if (backtickMatch) { -          backtickCount = backtickMatch[0].length + 1; +      return theadText + tbodyText; +    }, +    'thead'(el, text) { +      const cells = _.map(el.querySelectorAll('th'), (cell) => { +        let chars = CopyAsGFM.nodeToGFM(cell).trim().length + 2; + +        let before = ''; +        let after = ''; +        switch (cell.style.textAlign) { +          case 'center': +            before = ':'; +            after = ':'; +            chars -= 2; +            break; +          case 'right': +            after = ':'; +            chars -= 1; +            break; +          default: +            break;          } -        const backticks = Array(backtickCount + 1).join('`'); -        const spaceOrNoSpace = backtickCount > 1 ? ' ' : ''; - -        return backticks + spaceOrNoSpace + text + spaceOrNoSpace + backticks; -      }, -      'blockquote'(el, text) { -        return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n'); -      }, -      'img'(el, text) { -        return `})`; -      }, -      'a.anchor'(el, text) { -        // Don't render a Markdown link for the anchor link inside a heading -        return text; -      }, -      'a'(el, text) { -        return `[${text}](${el.getAttribute('href')})`; -      }, -      'li'(el, text) { -        const lines = text.trim().split('\n'); -        const firstLine = `- ${lines.shift()}`; -        // Add four spaces to the front of subsequent list items lines, -        // or leave the line entirely blank. -        const nextLines = lines.map((s) => { -          if (s.trim().length === 0) return ''; - -          return `    ${s}`; -        }); - -        return `${firstLine}\n${nextLines.join('\n')}`; -      }, -      'ul'(el, text) { -        return text; -      }, -      'ol'(el, text) { -        // LIs get a `- ` prefix by default, which we replace by `1. ` for ordered lists. -        return text.replace(/^- /mg, '1. '); -      }, -      'h1'(el, text) { -        return `# ${text.trim()}`; -      }, -      'h2'(el, text) { -        return `## ${text.trim()}`; -      }, -      'h3'(el, text) { -        return `### ${text.trim()}`; -      }, -      'h4'(el, text) { -        return `#### ${text.trim()}`; -      }, -      'h5'(el, text) { -        return `##### ${text.trim()}`; -      }, -      'h6'(el, text) { -        return `###### ${text.trim()}`; -      }, -      'strong'(el, text) { -        return `**${text}**`; -      }, -      'em'(el, text) { -        return `_${text}_`; -      }, -      'del'(el, text) { -        return `~~${text}~~`; -      }, -      'sup'(el, text) { -        return `^${text}`; -      }, -      'hr'(el, text) { -        return '-----'; -      }, -      'table'(el, text) { -        const theadEl = el.querySelector('thead'); -        const tbodyEl = el.querySelector('tbody'); -        if (!theadEl || !tbodyEl) return false; - -        const theadText = CopyAsGFM.nodeToGFM(theadEl); -        const tbodyText = CopyAsGFM.nodeToGFM(tbodyEl); - -        return theadText + tbodyText; -      }, -      'thead'(el, text) { -        const cells = _.map(el.querySelectorAll('th'), (cell) => { -          let chars = CopyAsGFM.nodeToGFM(cell).trim().length + 2; - -          let before = ''; -          let after = ''; -          switch (cell.style.textAlign) { -            case 'center': -              before = ':'; -              after = ':'; -              chars -= 2; -              break; -            case 'right': -              after = ':'; -              chars -= 1; -              break; -            default: -              break; -          } - -          chars = Math.max(chars, 3); - -          const middle = Array(chars + 1).join('-'); - -          return before + middle + after; -        }); - -        return `${text}|${cells.join('|')}|`; -      }, -      'tr'(el, text) { -        const cells = _.map(el.querySelectorAll('td, th'), cell => CopyAsGFM.nodeToGFM(cell).trim()); -        return `| ${cells.join(' | ')} |`; -      }, -    }, -  }; - -  class CopyAsGFM { -    constructor() { -      $(document).on('copy', '.md, .wiki', this.handleCopy); -      $(document).on('paste', '.js-gfm-input', this.handlePaste); -    } - -    handleCopy(e) { -      const clipboardData = e.originalEvent.clipboardData; -      if (!clipboardData) return; - -      const documentFragment = window.gl.utils.getSelectedFragment(); -      if (!documentFragment) return; +        chars = Math.max(chars, 3); -      // If the documentFragment contains more than just Markdown, don't copy as GFM. -      if (documentFragment.querySelector('.md, .wiki')) return; +        const middle = Array(chars + 1).join('-'); -      e.preventDefault(); -      clipboardData.setData('text/plain', documentFragment.textContent); +        return before + middle + after; +      }); -      const gfm = CopyAsGFM.nodeToGFM(documentFragment); -      clipboardData.setData('text/x-gfm', gfm); -    } +      return `${text}|${cells.join('|')}|`; +    }, +    'tr'(el, text) { +      const cells = _.map(el.querySelectorAll('td, th'), cell => CopyAsGFM.nodeToGFM(cell).trim()); +      return `| ${cells.join(' | ')} |`; +    }, +  }, +}; -    handlePaste(e) { -      const clipboardData = e.originalEvent.clipboardData; -      if (!clipboardData) return; +class CopyAsGFM { +  constructor() { +    $(document).on('copy', '.md, .wiki', this.handleCopy); +    $(document).on('paste', '.js-gfm-input', this.handlePaste); +  } -      const gfm = clipboardData.getData('text/x-gfm'); -      if (!gfm) return; +  handleCopy(e) { +    const clipboardData = e.originalEvent.clipboardData; +    if (!clipboardData) return; -      e.preventDefault(); +    const documentFragment = window.gl.utils.getSelectedFragment(); +    if (!documentFragment) return; -      window.gl.utils.insertText(e.target, gfm); -    } +    // If the documentFragment contains more than just Markdown, don't copy as GFM. +    if (documentFragment.querySelector('.md, .wiki')) return; -    static nodeToGFM(node) { -      if (node.nodeType === Node.TEXT_NODE) { -        return node.textContent; -      } +    e.preventDefault(); +    clipboardData.setData('text/plain', documentFragment.textContent); -      const text = this.innerGFM(node); +    const gfm = CopyAsGFM.nodeToGFM(documentFragment); +    clipboardData.setData('text/x-gfm', gfm); +  } -      if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { -        return text; -      } +  handlePaste(e) { +    const clipboardData = e.originalEvent.clipboardData; +    if (!clipboardData) return; -      for (const filter in gfmRules) { -        const rules = gfmRules[filter]; +    const gfm = clipboardData.getData('text/x-gfm'); +    if (!gfm) return; -        for (const selector in rules) { -          const func = rules[selector]; +    e.preventDefault(); -          if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue; +    window.gl.utils.insertText(e.target, gfm); +  } -          const result = func(node, text); -          if (result === false) continue; +  static nodeToGFM(node) { +    if (node.nodeType === Node.TEXT_NODE) { +      return node.textContent; +    } -          return result; -        } -      } +    const text = this.innerGFM(node); +    if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {        return text;      } -    static innerGFM(parentNode) { -      const nodes = parentNode.childNodes; +    for (const filter in gfmRules) { +      const rules = gfmRules[filter]; -      const clonedParentNode = parentNode.cloneNode(true); -      const clonedNodes = Array.prototype.slice.call(clonedParentNode.childNodes, 0); +      for (const selector in rules) { +        const func = rules[selector]; -      for (let i = 0; i < nodes.length; i += 1) { -        const node = nodes[i]; -        const clonedNode = clonedNodes[i]; +        if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue; -        const text = this.nodeToGFM(node); +        const result = func(node, text); +        if (result === false) continue; -        // `clonedNode.replaceWith(text)` is not yet widely supported -        clonedNode.parentNode.replaceChild(document.createTextNode(text), clonedNode); +        return result;        } +    } + +    return text; +  } -      return clonedParentNode.innerText || clonedParentNode.textContent; +  static innerGFM(parentNode) { +    const nodes = parentNode.childNodes; + +    const clonedParentNode = parentNode.cloneNode(true); +    const clonedNodes = Array.prototype.slice.call(clonedParentNode.childNodes, 0); + +    for (let i = 0; i < nodes.length; i += 1) { +      const node = nodes[i]; +      const clonedNode = clonedNodes[i]; + +      const text = this.nodeToGFM(node); + +      // `clonedNode.replaceWith(text)` is not yet widely supported +      clonedNode.parentNode.replaceChild(document.createTextNode(text), clonedNode);      } + +    return clonedParentNode.innerText || clonedParentNode.textContent;    } +} -  window.gl = window.gl || {}; -  window.gl.CopyAsGFM = CopyAsGFM; +window.gl = window.gl || {}; +window.gl.CopyAsGFM = CopyAsGFM; -  new CopyAsGFM(); -})(); +new CopyAsGFM(); diff --git a/app/assets/javascripts/copy_to_clipboard.js b/app/assets/javascripts/copy_to_clipboard.js index 615f485e18a..6dbec50b890 100644 --- a/app/assets/javascripts/copy_to_clipboard.js +++ b/app/assets/javascripts/copy_to_clipboard.js @@ -1,49 +1,46 @@  /* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, max-len */ -/* global Clipboard */ - -window.Clipboard = require('vendor/clipboard'); - -(function() { -  var genericError, genericSuccess, showTooltip; - -  genericSuccess = function(e) { -    showTooltip(e.trigger, 'Copied'); -    // Clear the selection and blur the trigger so it loses its border -    e.clearSelection(); -    return $(e.trigger).blur(); -  }; - -  // Safari doesn't support `execCommand`, so instead we inform the user to -  // copy manually. -  // -  // See http://clipboardjs.com/#browser-support -  genericError = function(e) { -    var key; -    if (/Mac/i.test(navigator.userAgent)) { -      key = '⌘'; // Command -    } else { -      key = 'Ctrl'; -    } -    return showTooltip(e.trigger, "Press " + key + "-C to copy"); -  }; - -  showTooltip = function(target, title) { -    var $target = $(target); -    var originalTitle = $target.data('original-title'); - -    $target -      .attr('title', 'Copied') -      .tooltip('fixTitle') -      .tooltip('show') -      .attr('title', originalTitle) -      .tooltip('fixTitle'); -  }; - -  $(function() { -    var clipboard; - -    clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]'); -    clipboard.on('success', genericSuccess); -    return clipboard.on('error', genericError); -  }); -}).call(window); + +import Clipboard from 'vendor/clipboard'; + +var genericError, genericSuccess, showTooltip; + +genericSuccess = function(e) { +  showTooltip(e.trigger, 'Copied'); +  // Clear the selection and blur the trigger so it loses its border +  e.clearSelection(); +  return $(e.trigger).blur(); +}; + +// Safari doesn't support `execCommand`, so instead we inform the user to +// copy manually. +// +// See http://clipboardjs.com/#browser-support +genericError = function(e) { +  var key; +  if (/Mac/i.test(navigator.userAgent)) { +    key = '⌘'; // Command +  } else { +    key = 'Ctrl'; +  } +  return showTooltip(e.trigger, "Press " + key + "-C to copy"); +}; + +showTooltip = function(target, title) { +  var $target = $(target); +  var originalTitle = $target.data('original-title'); + +  $target +    .attr('title', 'Copied') +    .tooltip('fixTitle') +    .tooltip('show') +    .attr('title', originalTitle) +    .tooltip('fixTitle'); +}; + +$(function() { +  var clipboard; + +  clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]'); +  clipboard.on('success', genericSuccess); +  return clipboard.on('error', genericError); +}); diff --git a/app/assets/javascripts/create_label.js b/app/assets/javascripts/create_label.js index 85384d98126..121d64db789 100644 --- a/app/assets/javascripts/create_label.js +++ b/app/assets/javascripts/create_label.js @@ -1,132 +1,127 @@  /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, comma-dangle, prefer-template, quotes, no-param-reassign, wrap-iife, max-len */  /* global Api */ -(function (w) { -  class CreateLabelDropdown { -    constructor ($el, namespacePath, projectPath) { -      this.$el = $el; -      this.namespacePath = namespacePath; -      this.projectPath = projectPath; -      this.$dropdownBack = $('.dropdown-menu-back', this.$el.closest('.dropdown')); -      this.$cancelButton = $('.js-cancel-label-btn', this.$el); -      this.$newLabelField = $('#new_label_name', this.$el); -      this.$newColorField = $('#new_label_color', this.$el); -      this.$colorPreview = $('.js-dropdown-label-color-preview', this.$el); -      this.$newLabelError = $('.js-label-error', this.$el); -      this.$newLabelCreateButton = $('.js-new-label-btn', this.$el); -      this.$colorSuggestions = $('.suggest-colors-dropdown a', this.$el); - -      this.$newLabelError.hide(); -      this.$newLabelCreateButton.disable(); +class CreateLabelDropdown { +  constructor ($el, namespacePath, projectPath) { +    this.$el = $el; +    this.namespacePath = namespacePath; +    this.projectPath = projectPath; +    this.$dropdownBack = $('.dropdown-menu-back', this.$el.closest('.dropdown')); +    this.$cancelButton = $('.js-cancel-label-btn', this.$el); +    this.$newLabelField = $('#new_label_name', this.$el); +    this.$newColorField = $('#new_label_color', this.$el); +    this.$colorPreview = $('.js-dropdown-label-color-preview', this.$el); +    this.$newLabelError = $('.js-label-error', this.$el); +    this.$newLabelCreateButton = $('.js-new-label-btn', this.$el); +    this.$colorSuggestions = $('.suggest-colors-dropdown a', this.$el); + +    this.$newLabelError.hide(); +    this.$newLabelCreateButton.disable(); + +    this.cleanBinding(); +    this.addBinding(); +  } -      this.cleanBinding(); -      this.addBinding(); -    } +  cleanBinding () { +    this.$colorSuggestions.off('click'); +    this.$newLabelField.off('keyup change'); +    this.$newColorField.off('keyup change'); +    this.$dropdownBack.off('click'); +    this.$cancelButton.off('click'); +    this.$newLabelCreateButton.off('click'); +  } -    cleanBinding () { -      this.$colorSuggestions.off('click'); -      this.$newLabelField.off('keyup change'); -      this.$newColorField.off('keyup change'); -      this.$dropdownBack.off('click'); -      this.$cancelButton.off('click'); -      this.$newLabelCreateButton.off('click'); -    } +  addBinding () { +    const self = this; -    addBinding () { -      const self = this; +    this.$colorSuggestions.on('click', function (e) { +      const $this = $(this); +      self.addColorValue(e, $this); +    }); -      this.$colorSuggestions.on('click', function (e) { -        const $this = $(this); -        self.addColorValue(e, $this); -      }); +    this.$newLabelField.on('keyup change', this.enableLabelCreateButton.bind(this)); +    this.$newColorField.on('keyup change', this.enableLabelCreateButton.bind(this)); -      this.$newLabelField.on('keyup change', this.enableLabelCreateButton.bind(this)); -      this.$newColorField.on('keyup change', this.enableLabelCreateButton.bind(this)); +    this.$dropdownBack.on('click', this.resetForm.bind(this)); -      this.$dropdownBack.on('click', this.resetForm.bind(this)); +    this.$cancelButton.on('click', function(e) { +      e.preventDefault(); +      e.stopPropagation(); -      this.$cancelButton.on('click', function(e) { -        e.preventDefault(); -        e.stopPropagation(); +      self.resetForm(); +      self.$dropdownBack.trigger('click'); +    }); -        self.resetForm(); -        self.$dropdownBack.trigger('click'); -      }); +    this.$newLabelCreateButton.on('click', this.saveLabel.bind(this)); +  } -      this.$newLabelCreateButton.on('click', this.saveLabel.bind(this)); -    } +  addColorValue (e, $this) { +    e.preventDefault(); +    e.stopPropagation(); -    addColorValue (e, $this) { -      e.preventDefault(); -      e.stopPropagation(); +    this.$newColorField.val($this.data('color')).trigger('change'); +    this.$colorPreview +      .css('background-color', $this.data('color')) +      .parent() +      .addClass('is-active'); +  } -      this.$newColorField.val($this.data('color')).trigger('change'); -      this.$colorPreview -        .css('background-color', $this.data('color')) -        .parent() -        .addClass('is-active'); +  enableLabelCreateButton () { +    if (this.$newLabelField.val() !== '' && this.$newColorField.val() !== '') { +      this.$newLabelError.hide(); +      this.$newLabelCreateButton.enable(); +    } else { +      this.$newLabelCreateButton.disable();      } +  } -    enableLabelCreateButton () { -      if (this.$newLabelField.val() !== '' && this.$newColorField.val() !== '') { -        this.$newLabelError.hide(); -        this.$newLabelCreateButton.enable(); -      } else { -        this.$newLabelCreateButton.disable(); -      } -    } +  resetForm () { +    this.$newLabelField +      .val('') +      .trigger('change'); -    resetForm () { -      this.$newLabelField -        .val('') -        .trigger('change'); +    this.$newColorField +      .val('') +      .trigger('change'); -      this.$newColorField -        .val('') -        .trigger('change'); +    this.$colorPreview +      .css('background-color', '') +      .parent() +      .removeClass('is-active'); +  } -      this.$colorPreview -        .css('background-color', '') -        .parent() -        .removeClass('is-active'); -    } +  saveLabel (e) { +    e.preventDefault(); +    e.stopPropagation(); -    saveLabel (e) { -      e.preventDefault(); -      e.stopPropagation(); +    Api.newLabel(this.namespacePath, this.projectPath, { +      title: this.$newLabelField.val(), +      color: this.$newColorField.val() +    }, (label) => { +      this.$newLabelCreateButton.enable(); -      Api.newLabel(this.namespacePath, this.projectPath, { -        title: this.$newLabelField.val(), -        color: this.$newColorField.val() -      }, (label) => { -        this.$newLabelCreateButton.enable(); - -        if (label.message) { -          let errors; - -          if (typeof label.message === 'string') { -            errors = label.message; -          } else { -            errors = Object.keys(label.message).map(key => -              `${gl.text.humanize(key)} ${label.message[key].join(', ')}` -            ).join("<br/>"); -          } - -          this.$newLabelError -            .html(errors) -            .show(); -        } else { -          this.$dropdownBack.trigger('click'); +      if (label.message) { +        let errors; -          $(document).trigger('created.label', label); +        if (typeof label.message === 'string') { +          errors = label.message; +        } else { +          errors = Object.keys(label.message).map(key => +            `${gl.text.humanize(key)} ${label.message[key].join(', ')}` +          ).join("<br/>");          } -      }); -    } -  } -  if (!w.gl) { -    w.gl = {}; +        this.$newLabelError +          .html(errors) +          .show(); +      } else { +        this.$dropdownBack.trigger('click'); + +        $(document).trigger('created.label', label); +      } +    });    } +} -  gl.CreateLabelDropdown = CreateLabelDropdown; -})(window); +window.gl = window.gl || {}; +gl.CreateLabelDropdown = CreateLabelDropdown; diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js index 6829e8aeaea..cfa60325fcc 100644 --- a/app/assets/javascripts/diff.js +++ b/app/assets/javascripts/diff.js @@ -2,129 +2,127 @@  require('./lib/utils/url_utility'); -(() => { -  const UNFOLD_COUNT = 20; -  let isBound = false; +const UNFOLD_COUNT = 20; +let isBound = false; -  class Diff { -    constructor() { -      const $diffFile = $('.files .diff-file'); -      $diffFile.singleFileDiff(); -      $diffFile.filesCommentButton(); +class Diff { +  constructor() { +    const $diffFile = $('.files .diff-file'); +    $diffFile.singleFileDiff(); +    $diffFile.filesCommentButton(); -      $diffFile.each((index, file) => new gl.ImageFile(file)); +    $diffFile.each((index, file) => new gl.ImageFile(file)); -      if (this.diffViewType() === 'parallel') { -        $('.content-wrapper .container-fluid').removeClass('container-limited'); -      } - -      if (!isBound) { -        $(document) -          .on('click', '.js-unfold', this.handleClickUnfold.bind(this)) -          .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this)); -        isBound = true; -      } +    if (this.diffViewType() === 'parallel') { +      $('.content-wrapper .container-fluid').removeClass('container-limited'); +    } -      if (gl.utils.getLocationHash()) { -        this.highlightSelectedLine(); -      } +    if (!isBound) { +      $(document) +        .on('click', '.js-unfold', this.handleClickUnfold.bind(this)) +        .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this)); +      isBound = true; +    } -      this.openAnchoredDiff(); +    if (gl.utils.getLocationHash()) { +      this.highlightSelectedLine();      } -    handleClickUnfold(e) { -      const $target = $(e.target); -      // current babel config relies on iterators implementation, so we cannot simply do: -      // const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent()); -      const ref = this.lineNumbers($target.parent()); -      const oldLineNumber = ref[0]; -      const newLineNumber = ref[1]; -      const offset = newLineNumber - oldLineNumber; -      const bottom = $target.hasClass('js-unfold-bottom'); -      let since; -      let to; -      let unfold = true; - -      if (bottom) { -        const lineNumber = newLineNumber + 1; -        since = lineNumber; -        to = lineNumber + UNFOLD_COUNT; -      } else { -        const lineNumber = newLineNumber - 1; -        since = lineNumber - UNFOLD_COUNT; -        to = lineNumber; - -        // make sure we aren't loading more than we need -        const prevNewLine = this.lineNumbers($target.parent().prev())[1]; -        if (since <= prevNewLine + 1) { -          since = prevNewLine + 1; -          unfold = false; -        } +    this.openAnchoredDiff(); +  } + +  handleClickUnfold(e) { +    const $target = $(e.target); +    // current babel config relies on iterators implementation, so we cannot simply do: +    // const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent()); +    const ref = this.lineNumbers($target.parent()); +    const oldLineNumber = ref[0]; +    const newLineNumber = ref[1]; +    const offset = newLineNumber - oldLineNumber; +    const bottom = $target.hasClass('js-unfold-bottom'); +    let since; +    let to; +    let unfold = true; + +    if (bottom) { +      const lineNumber = newLineNumber + 1; +      since = lineNumber; +      to = lineNumber + UNFOLD_COUNT; +    } else { +      const lineNumber = newLineNumber - 1; +      since = lineNumber - UNFOLD_COUNT; +      to = lineNumber; + +      // make sure we aren't loading more than we need +      const prevNewLine = this.lineNumbers($target.parent().prev())[1]; +      if (since <= prevNewLine + 1) { +        since = prevNewLine + 1; +        unfold = false;        } +    } -      const file = $target.parents('.diff-file'); -      const link = file.data('blob-diff-path'); -      const view = file.data('view'); +    const file = $target.parents('.diff-file'); +    const link = file.data('blob-diff-path'); +    const view = file.data('view'); -      const params = { since, to, bottom, offset, unfold, view }; -      $.get(link, params, response => $target.parent().replaceWith(response)); -    } +    const params = { since, to, bottom, offset, unfold, view }; +    $.get(link, params, response => $target.parent().replaceWith(response)); +  } -    openAnchoredDiff(cb) { -      const locationHash = gl.utils.getLocationHash(); -      const anchoredDiff = locationHash && locationHash.split('_')[0]; - -      if (!anchoredDiff) return; - -      const diffTitle = $(`#${anchoredDiff}`); -      const diffFile = diffTitle.closest('.diff-file'); -      const nothingHereBlock = $('.nothing-here-block:visible', diffFile); -      if (nothingHereBlock.length) { -        const clickTarget = $('.js-file-title, .click-to-expand', diffFile); -        diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { -          this.highlightSelectedLine(); -          if (cb) cb(); -        }); -      } else if (cb) { -        cb(); -      } -    } +  openAnchoredDiff(cb) { +    const locationHash = gl.utils.getLocationHash(); +    const anchoredDiff = locationHash && locationHash.split('_')[0]; -    handleClickLineNum(e) { -      const hash = $(e.currentTarget).attr('href'); -      e.preventDefault(); -      if (window.history.pushState) { -        window.history.pushState(null, null, hash); -      } else { -        window.location.hash = hash; -      } -      this.highlightSelectedLine(); +    if (!anchoredDiff) return; + +    const diffTitle = $(`#${anchoredDiff}`); +    const diffFile = diffTitle.closest('.diff-file'); +    const nothingHereBlock = $('.nothing-here-block:visible', diffFile); +    if (nothingHereBlock.length) { +      const clickTarget = $('.js-file-title, .click-to-expand', diffFile); +      diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { +        this.highlightSelectedLine(); +        if (cb) cb(); +      }); +    } else if (cb) { +      cb();      } +  } -    diffViewType() { -      return $('.inline-parallel-buttons a.active').data('view-type'); +  handleClickLineNum(e) { +    const hash = $(e.currentTarget).attr('href'); +    e.preventDefault(); +    if (window.history.pushState) { +      window.history.pushState(null, null, hash); +    } else { +      window.location.hash = hash;      } +    this.highlightSelectedLine(); +  } -    lineNumbers(line) { -      if (!line.children().length) { -        return [0, 0]; -      } -      return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10)); +  diffViewType() { +    return $('.inline-parallel-buttons a.active').data('view-type'); +  } + +  lineNumbers(line) { +    if (!line.children().length) { +      return [0, 0];      } +    return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10)); +  } -    highlightSelectedLine() { -      const hash = gl.utils.getLocationHash(); -      const $diffFiles = $('.diff-file'); -      $diffFiles.find('.hll').removeClass('hll'); +  highlightSelectedLine() { +    const hash = gl.utils.getLocationHash(); +    const $diffFiles = $('.diff-file'); +    $diffFiles.find('.hll').removeClass('hll'); -      if (hash) { -        $diffFiles -          .find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`) -          .addClass('hll'); -      } +    if (hash) { +      $diffFiles +        .find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`) +        .addClass('hll');      }    } +} -  window.gl = window.gl || {}; -  window.gl.Diff = Diff; -})(); +window.gl = window.gl || {}; +window.gl.Diff = Diff; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index 646f836aff0..f2963a5eb19 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -3,218 +3,216 @@  require('./preview_markdown'); -(function() { -  this.DropzoneInput = (function() { -    function DropzoneInput(form) { -      var $mdArea, alertAttr, alertClass, appendToTextArea, btnAlert, child, closeAlertMessage, closeSpinner, divAlert, divHover, divSpinner, dropzone, form_dropzone, form_textarea, getFilename, handlePaste, iconPaperclip, iconSpinner, insertToTextArea, isImage, max_file_size, pasteText, project_uploads_path, showError, showSpinner, uploadFile, uploadProgress; -      Dropzone.autoDiscover = false; -      alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"; -      alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""; -      divHover = "<div class=\"div-dropzone-hover\"></div>"; -      divSpinner = "<div class=\"div-dropzone-spinner\"></div>"; -      divAlert = "<div class=\"" + alertClass + "\"></div>"; -      iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>"; -      iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"; -      uploadProgress = $("<div class=\"div-dropzone-progress\"></div>"); -      btnAlert = "<button type=\"button\"" + alertAttr + ">×</button>"; -      project_uploads_path = window.project_uploads_path || null; -      max_file_size = gon.max_file_size || 10; -      form_textarea = $(form).find(".js-gfm-input"); -      form_textarea.wrap("<div class=\"div-dropzone\"></div>"); -      form_textarea.on('paste', (function(_this) { -        return function(event) { -          return handlePaste(event); -        }; -      })(this)); -      $mdArea = $(form_textarea).closest('.md-area'); -      $(form).setupMarkdownPreview(); -      form_dropzone = $(form).find('.div-dropzone'); -      form_dropzone.parent().addClass("div-dropzone-wrapper"); -      form_dropzone.append(divHover); -      form_dropzone.find(".div-dropzone-hover").append(iconPaperclip); -      form_dropzone.append(divSpinner); -      form_dropzone.find(".div-dropzone-spinner").append(iconSpinner); -      form_dropzone.find(".div-dropzone-spinner").append(uploadProgress); -      form_dropzone.find(".div-dropzone-spinner").css({ -        "opacity": 0, -        "display": "none" -      }); -      dropzone = form_dropzone.dropzone({ -        url: project_uploads_path, -        dictDefaultMessage: "", -        clickable: true, -        paramName: "file", -        maxFilesize: max_file_size, -        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); -          form_textarea.focus(); -        }, -        success: function(header, response) { -          pasteText(response.link.markdown); -        }, -        error: function(temp) { -          var checkIfMsgExists, errorAlert; -          errorAlert = $(form).find('.error-alert'); -          checkIfMsgExists = errorAlert.children().length; -          if (checkIfMsgExists === 0) { -            errorAlert.append(divAlert); -            $(".div-dropzone-alert").append(btnAlert + "Attaching the file failed."); -          } -        }, -        totaluploadprogress: function(totalUploadProgress) { -          uploadProgress.text(Math.round(totalUploadProgress) + "%"); -        }, -        sending: function() { -          form_dropzone.find(".div-dropzone-spinner").css({ -            "opacity": 0.7, -            "display": "inherit" -          }); -        }, -        queuecomplete: function() { -          uploadProgress.text(""); -          $(".dz-preview").remove(); -          $(".markdown-area").trigger("input"); -          $(".div-dropzone-spinner").css({ -            "opacity": 0, -            "display": "none" -          }); -        } -      }); -      child = $(dropzone[0]).children("textarea"); -      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); -          } -        } +window.DropzoneInput = (function() { +  function DropzoneInput(form) { +    var $mdArea, alertAttr, alertClass, appendToTextArea, btnAlert, child, closeAlertMessage, closeSpinner, divAlert, divHover, divSpinner, dropzone, form_dropzone, form_textarea, getFilename, handlePaste, iconPaperclip, iconSpinner, insertToTextArea, isImage, max_file_size, pasteText, project_uploads_path, showError, showSpinner, uploadFile, uploadProgress; +    Dropzone.autoDiscover = false; +    alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"; +    alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""; +    divHover = "<div class=\"div-dropzone-hover\"></div>"; +    divSpinner = "<div class=\"div-dropzone-spinner\"></div>"; +    divAlert = "<div class=\"" + alertClass + "\"></div>"; +    iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>"; +    iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"; +    uploadProgress = $("<div class=\"div-dropzone-progress\"></div>"); +    btnAlert = "<button type=\"button\"" + alertAttr + ">×</button>"; +    project_uploads_path = window.project_uploads_path || null; +    max_file_size = gon.max_file_size || 10; +    form_textarea = $(form).find(".js-gfm-input"); +    form_textarea.wrap("<div class=\"div-dropzone\"></div>"); +    form_textarea.on('paste', (function(_this) { +      return function(event) { +        return handlePaste(event);        }; -      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) { -        var afterSelection, beforeSelection, caretEnd, caretStart, textEnd; -        var formattedText = text + "\n\n"; -        caretStart = $(child)[0].selectionStart; -        caretEnd = $(child)[0].selectionEnd; -        textEnd = $(child).val().length; -        beforeSelection = $(child).val().substring(0, caretStart); -        afterSelection = $(child).val().substring(caretEnd, textEnd); -        $(child).val(beforeSelection + formattedText + afterSelection); -        child.get(0).setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length); -        return form_textarea.trigger("input"); -      }; -      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"); +    })(this)); +    $mdArea = $(form_textarea).closest('.md-area'); +    $(form).setupMarkdownPreview(); +    form_dropzone = $(form).find('.div-dropzone'); +    form_dropzone.parent().addClass("div-dropzone-wrapper"); +    form_dropzone.append(divHover); +    form_dropzone.find(".div-dropzone-hover").append(iconPaperclip); +    form_dropzone.append(divSpinner); +    form_dropzone.find(".div-dropzone-spinner").append(iconSpinner); +    form_dropzone.find(".div-dropzone-spinner").append(uploadProgress); +    form_dropzone.find(".div-dropzone-spinner").css({ +      "opacity": 0, +      "display": "none" +    }); +    dropzone = form_dropzone.dropzone({ +      url: project_uploads_path, +      dictDefaultMessage: "", +      clickable: true, +      paramName: "file", +      maxFilesize: max_file_size, +      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); +        form_textarea.focus(); +      }, +      success: function(header, response) { +        pasteText(response.link.markdown); +      }, +      error: function(temp) { +        var checkIfMsgExists, errorAlert; +        errorAlert = $(form).find('.error-alert'); +        checkIfMsgExists = errorAlert.children().length; +        if (checkIfMsgExists === 0) { +          errorAlert.append(divAlert); +          $(".div-dropzone-alert").append(btnAlert + "Attaching the file failed.");          } -        value = value.split("\r"); -        return value.first(); -      }; -      uploadFile = function(item, filename) { -        var formData; -        formData = new FormData(); -        formData.append("file", item, filename); -        return $.ajax({ -          url: project_uploads_path, -          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(); -          } -        }); -      }; -      insertToTextArea = function(filename, url) { -        return $(child).val(function(index, val) { -          return val.replace("{{" + filename + "}}", url + "\n"); -        }); -      }; -      appendToTextArea = function(url) { -        return $(child).val(function(index, val) { -          return val + url + "\n"; -        }); -      }; -      showSpinner = function(e) { -        return form.find(".div-dropzone-spinner").css({ +      }, +      totaluploadprogress: function(totalUploadProgress) { +        uploadProgress.text(Math.round(totalUploadProgress) + "%"); +      }, +      sending: function() { +        form_dropzone.find(".div-dropzone-spinner").css({            "opacity": 0.7,            "display": "inherit"          }); -      }; -      closeSpinner = function() { -        return form.find(".div-dropzone-spinner").css({ +      }, +      queuecomplete: function() { +        uploadProgress.text(""); +        $(".dz-preview").remove(); +        $(".markdown-area").trigger("input"); +        $(".div-dropzone-spinner").css({            "opacity": 0,            "display": "none"          }); -      }; -      showError = function(message) { -        var checkIfMsgExists, errorAlert; -        errorAlert = $(form).find('.error-alert'); -        checkIfMsgExists = errorAlert.children().length; -        if (checkIfMsgExists === 0) { -          errorAlert.append(divAlert); -          return $(".div-dropzone-alert").append(btnAlert + message); +      } +    }); +    child = $(dropzone[0]).children("textarea"); +    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);          } -      }; -      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(); +      } +    }; +    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) { +      var afterSelection, beforeSelection, caretEnd, caretStart, textEnd; +      var formattedText = text + "\n\n"; +      caretStart = $(child)[0].selectionStart; +      caretEnd = $(child)[0].selectionEnd; +      textEnd = $(child).val().length; +      beforeSelection = $(child).val().substring(0, caretStart); +      afterSelection = $(child).val().substring(caretEnd, textEnd); +      $(child).val(beforeSelection + formattedText + afterSelection); +      child.get(0).setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length); +      return form_textarea.trigger("input"); +    }; +    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: project_uploads_path, +        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(); +        } +      }); +    }; +    insertToTextArea = function(filename, url) { +      return $(child).val(function(index, val) { +        return val.replace("{{" + filename + "}}", url + "\n"); +      }); +    }; +    appendToTextArea = function(url) { +      return $(child).val(function(index, val) { +        return val + url + "\n"; +      }); +    }; +    showSpinner = function(e) { +      return form.find(".div-dropzone-spinner").css({ +        "opacity": 0.7, +        "display": "inherit" +      }); +    }; +    closeSpinner = function() { +      return form.find(".div-dropzone-spinner").css({ +        "opacity": 0, +        "display": "none"        }); -    } +    }; +    showError = function(message) { +      var checkIfMsgExists, errorAlert; +      errorAlert = $(form).find('.error-alert'); +      checkIfMsgExists = errorAlert.children().length; +      if (checkIfMsgExists === 0) { +        errorAlert.append(divAlert); +        return $(".div-dropzone-alert").append(btnAlert + message); +      } +    }; +    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(); +    }); +  } -    return DropzoneInput; -  })(); -}).call(window); +  return DropzoneInput; +})(); diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js index 9169fcd7328..fdbb4644971 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -2,203 +2,202 @@  /* global dateFormat */  /* global Pikaday */ -(function(global) { -  class DueDateSelect { -    constructor({ $dropdown, $loading } = {}) { -      const $dropdownParent = $dropdown.closest('.dropdown'); -      const $block = $dropdown.closest('.block'); -      this.$loading = $loading; -      this.$dropdown = $dropdown; -      this.$dropdownParent = $dropdownParent; -      this.$datePicker = $dropdownParent.find('.js-due-date-calendar'); -      this.$block = $block; -      this.$selectbox = $dropdown.closest('.selectbox'); -      this.$value = $block.find('.value'); -      this.$valueContent = $block.find('.value-content'); -      this.$sidebarValue = $('.js-due-date-sidebar-value', $block); -      this.fieldName = $dropdown.data('field-name'), -      this.abilityName = $dropdown.data('ability-name'), -      this.issueUpdateURL = $dropdown.data('issue-update'); - -      this.rawSelectedDate = null; -      this.displayedDate = null; -      this.datePayload = null; - -      this.initGlDropdown(); -      this.initRemoveDueDate(); -      this.initDatePicker(); -    } - -    initGlDropdown() { -      this.$dropdown.glDropdown({ -        opened: () => { -          const calendar = this.$datePicker.data('pikaday'); -          calendar.show(); -        }, -        hidden: () => { -          this.$selectbox.hide(); -          this.$value.css('display', ''); -        } -      }); -    } - -    initDatePicker() { -      const $dueDateInput = $(`input[name='${this.fieldName}']`); - -      const calendar = new Pikaday({ -        field: $dueDateInput.get(0), -        theme: 'gitlab-theme', -        format: 'yyyy-mm-dd', -        onSelect: (dateText) => { -          const formattedDate = dateFormat(new Date(dateText), 'yyyy-mm-dd'); - -          $dueDateInput.val(formattedDate); +class DueDateSelect { +  constructor({ $dropdown, $loading } = {}) { +    const $dropdownParent = $dropdown.closest('.dropdown'); +    const $block = $dropdown.closest('.block'); +    this.$loading = $loading; +    this.$dropdown = $dropdown; +    this.$dropdownParent = $dropdownParent; +    this.$datePicker = $dropdownParent.find('.js-due-date-calendar'); +    this.$block = $block; +    this.$selectbox = $dropdown.closest('.selectbox'); +    this.$value = $block.find('.value'); +    this.$valueContent = $block.find('.value-content'); +    this.$sidebarValue = $('.js-due-date-sidebar-value', $block); +    this.fieldName = $dropdown.data('field-name'), +    this.abilityName = $dropdown.data('ability-name'), +    this.issueUpdateURL = $dropdown.data('issue-update'); + +    this.rawSelectedDate = null; +    this.displayedDate = null; +    this.datePayload = null; + +    this.initGlDropdown(); +    this.initRemoveDueDate(); +    this.initDatePicker(); +  } -          if (this.$dropdown.hasClass('js-issue-boards-due-date')) { -            gl.issueBoards.BoardsStore.detail.issue.dueDate = $dueDateInput.val(); -            this.updateIssueBoardIssue(); -          } else { -            this.saveDueDate(true); -          } -        } -      }); +  initGlDropdown() { +    this.$dropdown.glDropdown({ +      opened: () => { +        const calendar = this.$datePicker.data('pikaday'); +        calendar.show(); +      }, +      hidden: () => { +        this.$selectbox.hide(); +        this.$value.css('display', ''); +      } +    }); +  } -      calendar.setDate(new Date($dueDateInput.val())); -      this.$datePicker.append(calendar.el); -      this.$datePicker.data('pikaday', calendar); -    } +  initDatePicker() { +    const $dueDateInput = $(`input[name='${this.fieldName}']`); -    initRemoveDueDate() { -      this.$block.on('click', '.js-remove-due-date', (e) => { -        const calendar = this.$datePicker.data('pikaday'); -        e.preventDefault(); +    const calendar = new Pikaday({ +      field: $dueDateInput.get(0), +      theme: 'gitlab-theme', +      format: 'yyyy-mm-dd', +      onSelect: (dateText) => { +        const formattedDate = dateFormat(new Date(dateText), 'yyyy-mm-dd'); -        calendar.setDate(null); +        $dueDateInput.val(formattedDate);          if (this.$dropdown.hasClass('js-issue-boards-due-date')) { -          gl.issueBoards.BoardsStore.detail.issue.dueDate = ''; +          gl.issueBoards.BoardsStore.detail.issue.dueDate = $dueDateInput.val();            this.updateIssueBoardIssue();          } else { -          $("input[name='" + this.fieldName + "']").val(''); -          return this.saveDueDate(false); +          this.saveDueDate(true);          } -      }); -    } +      } +    }); -    saveDueDate(isDropdown) { -      this.parseSelectedDate(); -      this.prepSelectedDate(); -      this.submitSelectedDate(isDropdown); -    } +    calendar.setDate(new Date($dueDateInput.val())); +    this.$datePicker.append(calendar.el); +    this.$datePicker.data('pikaday', calendar); +  } + +  initRemoveDueDate() { +    this.$block.on('click', '.js-remove-due-date', (e) => { +      const calendar = this.$datePicker.data('pikaday'); +      e.preventDefault(); -    parseSelectedDate() { -      this.rawSelectedDate = $(`input[name='${this.fieldName}']`).val(); +      calendar.setDate(null); -      if (this.rawSelectedDate.length) { -        // Construct Date object manually to avoid buggy dateString support within Date constructor -        const dateArray = this.rawSelectedDate.split('-').map(v => parseInt(v, 10)); -        const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); -        this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy'); +      if (this.$dropdown.hasClass('js-issue-boards-due-date')) { +        gl.issueBoards.BoardsStore.detail.issue.dueDate = ''; +        this.updateIssueBoardIssue();        } else { -        this.displayedDate = 'No due date'; +        $("input[name='" + this.fieldName + "']").val(''); +        return this.saveDueDate(false);        } -    } +    }); +  } -    prepSelectedDate() { -      const datePayload = {}; -      datePayload[this.abilityName] = {}; -      datePayload[this.abilityName].due_date = this.rawSelectedDate; -      this.datePayload = datePayload; -    } +  saveDueDate(isDropdown) { +    this.parseSelectedDate(); +    this.prepSelectedDate(); +    this.submitSelectedDate(isDropdown); +  } -    updateIssueBoardIssue () { -      this.$loading.fadeIn(); -      this.$dropdown.trigger('loading.gl.dropdown'); -      this.$selectbox.hide(); -      this.$value.css('display', ''); +  parseSelectedDate() { +    this.rawSelectedDate = $(`input[name='${this.fieldName}']`).val(); -      gl.issueBoards.BoardsStore.detail.issue.update(this.$dropdown.attr('data-issue-update')) -        .then(() => { -          this.$loading.fadeOut(); -        }); +    if (this.rawSelectedDate.length) { +      // Construct Date object manually to avoid buggy dateString support within Date constructor +      const dateArray = this.rawSelectedDate.split('-').map(v => parseInt(v, 10)); +      const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); +      this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy'); +    } else { +      this.displayedDate = 'No due date';      } +  } + +  prepSelectedDate() { +    const datePayload = {}; +    datePayload[this.abilityName] = {}; +    datePayload[this.abilityName].due_date = this.rawSelectedDate; +    this.datePayload = datePayload; +  } + +  updateIssueBoardIssue () { +    this.$loading.fadeIn(); +    this.$dropdown.trigger('loading.gl.dropdown'); +    this.$selectbox.hide(); +    this.$value.css('display', ''); + +    gl.issueBoards.BoardsStore.detail.issue.update(this.$dropdown.attr('data-issue-update')) +      .then(() => { +        this.$loading.fadeOut(); +      }); +  } + +  submitSelectedDate(isDropdown) { +    return $.ajax({ +      type: 'PUT', +      url: this.issueUpdateURL, +      data: this.datePayload, +      dataType: 'json', +      beforeSend: () => { +        const selectedDateValue = this.datePayload[this.abilityName].due_date; +        const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value'; + +        this.$loading.fadeIn(); -    submitSelectedDate(isDropdown) { -      return $.ajax({ -        type: 'PUT', -        url: this.issueUpdateURL, -        data: this.datePayload, -        dataType: 'json', -        beforeSend: () => { -          const selectedDateValue = this.datePayload[this.abilityName].due_date; -          const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value'; - -          this.$loading.fadeIn(); - -          if (isDropdown) { -            this.$dropdown.trigger('loading.gl.dropdown'); -            this.$selectbox.hide(); -          } - -          this.$value.css('display', ''); -          this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`); -          this.$sidebarValue.html(this.displayedDate); - -          return selectedDateValue.length ? -            $('.js-remove-due-date-holder').removeClass('hidden') : -            $('.js-remove-due-date-holder').addClass('hidden'); -        } -      }).done((data) => {          if (isDropdown) { -          this.$dropdown.trigger('loaded.gl.dropdown'); -          this.$dropdown.dropdown('toggle'); +          this.$dropdown.trigger('loading.gl.dropdown'); +          this.$selectbox.hide();          } -        return this.$loading.fadeOut(); -      }); -    } + +        this.$value.css('display', ''); +        this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`); +        this.$sidebarValue.html(this.displayedDate); + +        return selectedDateValue.length ? +          $('.js-remove-due-date-holder').removeClass('hidden') : +          $('.js-remove-due-date-holder').addClass('hidden'); +      } +    }).done((data) => { +      if (isDropdown) { +        this.$dropdown.trigger('loaded.gl.dropdown'); +        this.$dropdown.dropdown('toggle'); +      } +      return this.$loading.fadeOut(); +    });    } +} -  class DueDateSelectors { -    constructor() { -      this.initMilestoneDatePicker(); -      this.initIssuableSelect(); -    } +class DueDateSelectors { +  constructor() { +    this.initMilestoneDatePicker(); +    this.initIssuableSelect(); +  } -    initMilestoneDatePicker() { -      $('.datepicker').each(function() { -        const $datePicker = $(this); -        const calendar = new Pikaday({ -          field: $datePicker.get(0), -          theme: 'gitlab-theme', -          format: 'yyyy-mm-dd', -          onSelect(dateText) { -            $datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); -          } -        }); -        calendar.setDate(new Date($datePicker.val())); - -        $datePicker.data('pikaday', calendar); +  initMilestoneDatePicker() { +    $('.datepicker').each(function() { +      const $datePicker = $(this); +      const calendar = new Pikaday({ +        field: $datePicker.get(0), +        theme: 'gitlab-theme', +        format: 'yyyy-mm-dd', +        onSelect(dateText) { +          $datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); +        }        }); +      calendar.setDate(new Date($datePicker.val())); -      $('.js-clear-due-date,.js-clear-start-date').on('click', (e) => { -        e.preventDefault(); -        const calendar = $(e.target).siblings('.datepicker').data('pikaday'); -        calendar.setDate(null); -      }); -    } +      $datePicker.data('pikaday', calendar); +    }); -    initIssuableSelect() { -      const $loading = $('.js-issuable-update .due_date').find('.block-loading').hide(); +    $('.js-clear-due-date,.js-clear-start-date').on('click', (e) => { +      e.preventDefault(); +      const calendar = $(e.target).siblings('.datepicker').data('pikaday'); +      calendar.setDate(null); +    }); +  } + +  initIssuableSelect() { +    const $loading = $('.js-issuable-update .due_date').find('.block-loading').hide(); -      $('.js-due-date-select').each((i, dropdown) => { -        const $dropdown = $(dropdown); -        new DueDateSelect({ -          $dropdown, -          $loading -        }); +    $('.js-due-date-select').each((i, dropdown) => { +      const $dropdown = $(dropdown); +      new DueDateSelect({ +        $dropdown, +        $loading        }); -    } +    });    } +} -  global.DueDateSelectors = DueDateSelectors; -})(window.gl || (window.gl = {})); +window.gl = window.gl || {}; +window.gl.DueDateSelectors = DueDateSelectors; diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js index bf84f2a0a8f..3f041172ff3 100644 --- a/app/assets/javascripts/files_comment_button.js +++ b/app/assets/javascripts/files_comment_button.js @@ -2,142 +2,140 @@  /* global FilesCommentButton */  /* global notes */ -(function() { -  let $commentButtonTemplate; -  var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +let $commentButtonTemplate; +var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; -  this.FilesCommentButton = (function() { -    var COMMENT_BUTTON_CLASS, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS; +window.FilesCommentButton = (function() { +  var COMMENT_BUTTON_CLASS, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS; -    COMMENT_BUTTON_CLASS = '.add-diff-note'; +  COMMENT_BUTTON_CLASS = '.add-diff-note'; -    LINE_HOLDER_CLASS = '.line_holder'; +  LINE_HOLDER_CLASS = '.line_holder'; -    LINE_NUMBER_CLASS = 'diff-line-num'; +  LINE_NUMBER_CLASS = 'diff-line-num'; -    LINE_CONTENT_CLASS = 'line_content'; +  LINE_CONTENT_CLASS = 'line_content'; -    UNFOLDABLE_LINE_CLASS = 'js-unfold'; +  UNFOLDABLE_LINE_CLASS = 'js-unfold'; -    EMPTY_CELL_CLASS = 'empty-cell'; +  EMPTY_CELL_CLASS = 'empty-cell'; -    OLD_LINE_CLASS = 'old_line'; +  OLD_LINE_CLASS = 'old_line'; -    LINE_COLUMN_CLASSES = "." + LINE_NUMBER_CLASS + ", .line_content"; +  LINE_COLUMN_CLASSES = "." + LINE_NUMBER_CLASS + ", .line_content"; -    TEXT_FILE_SELECTOR = '.text-file'; +  TEXT_FILE_SELECTOR = '.text-file'; -    function FilesCommentButton(filesContainerElement) { -      this.render = bind(this.render, this); -      this.hideButton = bind(this.hideButton, this); -      this.isParallelView = notes.isParallelView(); -      filesContainerElement.on('mouseover', LINE_COLUMN_CLASSES, this.render) -        .on('mouseleave', LINE_COLUMN_CLASSES, this.hideButton); +  function FilesCommentButton(filesContainerElement) { +    this.render = bind(this.render, this); +    this.hideButton = bind(this.hideButton, this); +    this.isParallelView = notes.isParallelView(); +    filesContainerElement.on('mouseover', LINE_COLUMN_CLASSES, this.render) +      .on('mouseleave', LINE_COLUMN_CLASSES, this.hideButton); +  } + +  FilesCommentButton.prototype.render = function(e) { +    var $currentTarget, buttonParentElement, lineContentElement, textFileElement, $button; +    $currentTarget = $(e.currentTarget); + +    if ($currentTarget.hasClass('js-no-comment-btn')) return; + +    lineContentElement = this.getLineContent($currentTarget); +    buttonParentElement = this.getButtonParent($currentTarget); + +    if (!this.validateButtonParent(buttonParentElement) || !this.validateLineContent(lineContentElement)) return; + +    $button = $(COMMENT_BUTTON_CLASS, buttonParentElement); +    buttonParentElement.addClass('is-over') +      .nextUntil(`.${LINE_CONTENT_CLASS}`).addClass('is-over'); + +    if ($button.length) { +      return;      } -    FilesCommentButton.prototype.render = function(e) { -      var $currentTarget, buttonParentElement, lineContentElement, textFileElement, $button; -      $currentTarget = $(e.currentTarget); +    textFileElement = this.getTextFileElement($currentTarget); +    buttonParentElement.append(this.buildButton({ +      noteableType: textFileElement.attr('data-noteable-type'), +      noteableID: textFileElement.attr('data-noteable-id'), +      commitID: textFileElement.attr('data-commit-id'), +      noteType: lineContentElement.attr('data-note-type'), +      position: lineContentElement.attr('data-position'), +      lineType: lineContentElement.attr('data-line-type'), +      discussionID: lineContentElement.attr('data-discussion-id'), +      lineCode: lineContentElement.attr('data-line-code') +    })); +  }; -      if ($currentTarget.hasClass('js-no-comment-btn')) return; +  FilesCommentButton.prototype.hideButton = function(e) { +    var $currentTarget = $(e.currentTarget); +    var buttonParentElement = this.getButtonParent($currentTarget); -      lineContentElement = this.getLineContent($currentTarget); -      buttonParentElement = this.getButtonParent($currentTarget); +    buttonParentElement.removeClass('is-over') +      .nextUntil(`.${LINE_CONTENT_CLASS}`).removeClass('is-over'); +  }; -      if (!this.validateButtonParent(buttonParentElement) || !this.validateLineContent(lineContentElement)) return; +  FilesCommentButton.prototype.buildButton = function(buttonAttributes) { +    return $commentButtonTemplate.clone().attr({ +      'data-noteable-type': buttonAttributes.noteableType, +      'data-noteable-id': buttonAttributes.noteableID, +      'data-commit-id': buttonAttributes.commitID, +      'data-note-type': buttonAttributes.noteType, +      'data-line-code': buttonAttributes.lineCode, +      'data-position': buttonAttributes.position, +      'data-discussion-id': buttonAttributes.discussionID, +      'data-line-type': buttonAttributes.lineType +    }); +  }; -      $button = $(COMMENT_BUTTON_CLASS, buttonParentElement); -      buttonParentElement.addClass('is-over') -        .nextUntil(`.${LINE_CONTENT_CLASS}`).addClass('is-over'); +  FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) { +    return hoveredElement.closest(TEXT_FILE_SELECTOR); +  }; -      if ($button.length) { -        return; -      } +  FilesCommentButton.prototype.getLineContent = function(hoveredElement) { +    if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) { +      return hoveredElement; +    } +    if (!this.isParallelView) { +      return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS); +    } else { +      return $(hoveredElement).next("." + LINE_CONTENT_CLASS); +    } +  }; -      textFileElement = this.getTextFileElement($currentTarget); -      buttonParentElement.append(this.buildButton({ -        noteableType: textFileElement.attr('data-noteable-type'), -        noteableID: textFileElement.attr('data-noteable-id'), -        commitID: textFileElement.attr('data-commit-id'), -        noteType: lineContentElement.attr('data-note-type'), -        position: lineContentElement.attr('data-position'), -        lineType: lineContentElement.attr('data-line-type'), -        discussionID: lineContentElement.attr('data-discussion-id'), -        lineCode: lineContentElement.attr('data-line-code') -      })); -    }; - -    FilesCommentButton.prototype.hideButton = function(e) { -      var $currentTarget = $(e.currentTarget); -      var buttonParentElement = this.getButtonParent($currentTarget); - -      buttonParentElement.removeClass('is-over') -        .nextUntil(`.${LINE_CONTENT_CLASS}`).removeClass('is-over'); -    }; - -    FilesCommentButton.prototype.buildButton = function(buttonAttributes) { -      return $commentButtonTemplate.clone().attr({ -        'data-noteable-type': buttonAttributes.noteableType, -        'data-noteable-id': buttonAttributes.noteableID, -        'data-commit-id': buttonAttributes.commitID, -        'data-note-type': buttonAttributes.noteType, -        'data-line-code': buttonAttributes.lineCode, -        'data-position': buttonAttributes.position, -        'data-discussion-id': buttonAttributes.discussionID, -        'data-line-type': buttonAttributes.lineType -      }); -    }; - -    FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) { -      return hoveredElement.closest(TEXT_FILE_SELECTOR); -    }; - -    FilesCommentButton.prototype.getLineContent = function(hoveredElement) { -      if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) { +  FilesCommentButton.prototype.getButtonParent = function(hoveredElement) { +    if (!this.isParallelView) { +      if (hoveredElement.hasClass(OLD_LINE_CLASS)) {          return hoveredElement;        } -      if (!this.isParallelView) { -        return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS); -      } else { -        return $(hoveredElement).next("." + LINE_CONTENT_CLASS); -      } -    }; - -    FilesCommentButton.prototype.getButtonParent = function(hoveredElement) { -      if (!this.isParallelView) { -        if (hoveredElement.hasClass(OLD_LINE_CLASS)) { -          return hoveredElement; -        } -        return hoveredElement.parent().find("." + OLD_LINE_CLASS); -      } else { -        if (hoveredElement.hasClass(LINE_NUMBER_CLASS)) { -          return hoveredElement; -        } -        return $(hoveredElement).prev("." + LINE_NUMBER_CLASS); +      return hoveredElement.parent().find("." + OLD_LINE_CLASS); +    } else { +      if (hoveredElement.hasClass(LINE_NUMBER_CLASS)) { +        return hoveredElement;        } -    }; +      return $(hoveredElement).prev("." + LINE_NUMBER_CLASS); +    } +  }; -    FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) { -      return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS); -    }; +  FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) { +    return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS); +  }; -    FilesCommentButton.prototype.validateLineContent = function(lineContentElement) { -      return lineContentElement.attr('data-discussion-id') && lineContentElement.attr('data-discussion-id') !== ''; -    }; +  FilesCommentButton.prototype.validateLineContent = function(lineContentElement) { +    return lineContentElement.attr('data-discussion-id') && lineContentElement.attr('data-discussion-id') !== ''; +  }; -    return FilesCommentButton; -  })(); +  return FilesCommentButton; +})(); -  $.fn.filesCommentButton = function() { -    $commentButtonTemplate = $('<button name="button" type="submit" class="add-diff-note js-add-diff-note-button" title="Add a comment to this line"><i class="fa fa-comment-o"></i></button>'); +$.fn.filesCommentButton = function() { +  $commentButtonTemplate = $('<button name="button" type="submit" class="add-diff-note js-add-diff-note-button" title="Add a comment to this line"><i class="fa fa-comment-o"></i></button>'); -    if (!(this && (this.parent().data('can-create-note') != null))) { -      return; +  if (!(this && (this.parent().data('can-create-note') != null))) { +    return; +  } +  return this.each(function() { +    if (!$.data(this, 'filesCommentButton')) { +      return $.data(this, 'filesCommentButton', new FilesCommentButton($(this)));      } -    return this.each(function() { -      if (!$.data(this, 'filesCommentButton')) { -        return $.data(this, 'filesCommentButton', new FilesCommentButton($(this))); -      } -    }); -  }; -}).call(window); +  }); +}; diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js index 47a40e28461..aaaeb9bddb1 100644 --- a/app/assets/javascripts/filterable_list.js +++ b/app/assets/javascripts/filterable_list.js @@ -2,6 +2,7 @@   * Makes search request for content when user types a value in the search input.   * Updates the html content of the page with the received one.   */ +  export default class FilterableList {    constructor(form, filter, holder) {      this.filterForm = form; diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index 730104b89f9..eec30624ff2 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -1,42 +1,41 @@  /* 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 */ -(function() { -  this.Flash = (function() { -    var hideFlash; -    hideFlash = function() { -      return $(this).fadeOut(); -    }; +window.Flash = (function() { +  var hideFlash; -    function Flash(message, type, parent) { -      var flash, textDiv; -      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 (this.flashContainer.parent().hasClass('content-wrapper')) { -        textDiv.addClass('container-fluid container-limited'); -      } -      flash.appendTo(this.flashContainer); -      this.flashContainer.show(); +  hideFlash = function() { +    return $(this).fadeOut(); +  }; + +  function Flash(message, type, parent) { +    var flash, textDiv; +    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 (this.flashContainer.parent().hasClass('content-wrapper')) { +      textDiv.addClass('container-fluid container-limited');      } +    flash.appendTo(this.flashContainer); +    this.flashContainer.show(); +  } -    return Flash; -  })(); -}).call(window); +  return Flash; +})(); diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index 4f7ce1fa197..9ac4c49d697 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -5,390 +5,386 @@ import emojiAliases from 'emojis/aliases.json';  import { glEmojiTag } from '~/behaviors/gl_emoji';  // Creates the variables for setting up GFM auto-completion -(function() { -  if (window.gl == null) { -    window.gl = {}; -  } +window.gl = window.gl || {}; -  function sanitize(str) { -    return str.replace(/<(?:.|\n)*?>/gm, ''); -  } +function sanitize(str) { +  return str.replace(/<(?:.|\n)*?>/gm, ''); +} -  window.gl.GfmAutoComplete = { -    dataSources: {}, -    defaultLoadingData: ['loading'], -    cachedData: {}, -    isLoadingData: {}, -    atTypeMap: { -      ':': 'emojis', -      '@': 'members', -      '#': 'issues', -      '!': 'mergeRequests', -      '~': 'labels', -      '%': 'milestones', -      '/': 'commands' -    }, -    // Emoji -    Emoji: { -      templateFunction: function(name) { -        return `<li> -          ${name} ${glEmojiTag(name)} -        </li> -        `; +window.gl.GfmAutoComplete = { +  dataSources: {}, +  defaultLoadingData: ['loading'], +  cachedData: {}, +  isLoadingData: {}, +  atTypeMap: { +    ':': 'emojis', +    '@': 'members', +    '#': 'issues', +    '!': 'mergeRequests', +    '~': 'labels', +    '%': 'milestones', +    '/': 'commands' +  }, +  // Emoji +  Emoji: { +    templateFunction: function(name) { +      return `<li> +        ${name} ${glEmojiTag(name)} +      </li> +      `; +    } +  }, +  // Team Members +  Members: { +    template: '<li>${avatarTag} ${username} <small>${title}</small></li>' +  }, +  Labels: { +    template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>' +  }, +  // Issues and MergeRequests +  Issues: { +    template: '<li><small>${id}</small> ${title}</li>' +  }, +  // Milestones +  Milestones: { +    template: '<li>${title}</li>' +  }, +  Loading: { +    template: '<li style="pointer-events: none;"><i class="fa fa-refresh fa-spin"></i> Loading...</li>' +  }, +  DefaultOptions: { +    sorter: function(query, items, searchKey) { +      this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0; +      if (gl.GfmAutoComplete.isLoading(items)) { +        this.setting.highlightFirst = false; +        return items;        } +      return $.fn.atwho["default"].callbacks.sorter(query, items, searchKey);      }, -    // Team Members -    Members: { -      template: '<li>${avatarTag} ${username} <small>${title}</small></li>' -    }, -    Labels: { -      template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>' -    }, -    // Issues and MergeRequests -    Issues: { -      template: '<li><small>${id}</small> ${title}</li>' -    }, -    // Milestones -    Milestones: { -      template: '<li>${title}</li>' +    filter: function(query, data, searchKey) { +      if (gl.GfmAutoComplete.isLoading(data)) { +        gl.GfmAutoComplete.fetchData(this.$inputor, this.at); +        return data; +      } else { +        return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); +      }      }, -    Loading: { -      template: '<li style="pointer-events: none;"><i class="fa fa-refresh fa-spin"></i> Loading...</li>' +    beforeInsert: function(value) { +      if (value && !this.setting.skipSpecialCharacterTest) { +        var withoutAt = value.substring(1); +        if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"'; +      } +      return value;      }, -    DefaultOptions: { -      sorter: function(query, items, searchKey) { -        this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0; -        if (gl.GfmAutoComplete.isLoading(items)) { -          this.setting.highlightFirst = false; -          return items; -        } -        return $.fn.atwho["default"].callbacks.sorter(query, items, searchKey); -      }, -      filter: function(query, data, searchKey) { -        if (gl.GfmAutoComplete.isLoading(data)) { -          gl.GfmAutoComplete.fetchData(this.$inputor, this.at); -          return data; -        } else { -          return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); -        } -      }, -      beforeInsert: function(value) { -        if (value && !this.setting.skipSpecialCharacterTest) { -          var withoutAt = value.substring(1); -          if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"'; -        } -        return value; -      }, -      matcher: function (flag, subtext) { -        // The below is taken from At.js source -        // Tweaked to commands to start without a space only if char before is a non-word character -        // https://github.com/ichord/At.js -        var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar; -        atSymbolsWithBar = Object.keys(this.app.controllers).join('|'); -        atSymbolsWithoutBar = Object.keys(this.app.controllers).join(''); -        subtext = subtext.split(/\s+/g).pop(); -        flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); +    matcher: function (flag, subtext) { +      // The below is taken from At.js source +      // Tweaked to commands to start without a space only if char before is a non-word character +      // https://github.com/ichord/At.js +      var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar; +      atSymbolsWithBar = Object.keys(this.app.controllers).join('|'); +      atSymbolsWithoutBar = Object.keys(this.app.controllers).join(''); +      subtext = subtext.split(/\s+/g).pop(); +      flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); -        _a = decodeURI("%C3%80"); -        _y = decodeURI("%C3%BF"); +      _a = decodeURI("%C3%80"); +      _y = decodeURI("%C3%BF"); -        regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?!" + atSymbolsWithBar + ")((?:[A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]|[^\\x00-\\x7a])*)$", 'gi'); +      regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?!" + atSymbolsWithBar + ")((?:[A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]|[^\\x00-\\x7a])*)$", 'gi'); -        match = regexp.exec(subtext); +      match = regexp.exec(subtext); -        if (match) { -          return match[1]; -        } else { -          return null; -        } +      if (match) { +        return match[1]; +      } else { +        return null;        } -    }, -    setup: function(input) { -      // Add GFM auto-completion to all input fields, that accept GFM input. -      this.input = input || $('.js-gfm-input'); -      this.setupLifecycle(); -    }, -    setupLifecycle() { -      this.input.each((i, input) => { -        const $input = $(input); -        $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input)); -        // This triggers at.js again -        // Needed for slash commands with suffixes (ex: /label ~) -        $input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup')); -      }); -    }, -    setupAtWho: function($input) { -      // Emoji -      $input.atwho({ -        at: ':', -        displayTpl: function(value) { -          return value && value.name ? this.Emoji.templateFunction(value.name) : this.Loading.template; -        }.bind(this), -        insertTpl: ':${name}:', -        skipSpecialCharacterTest: true, -        data: this.defaultLoadingData, -        callbacks: { -          sorter: this.DefaultOptions.sorter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          filter: this.DefaultOptions.filter -        } -      }); -      // Team Members -      $input.atwho({ -        at: '@', -        displayTpl: function(value) { -          return value.username != null ? this.Members.template : this.Loading.template; -        }.bind(this), -        insertTpl: '${atwho-at}${username}', -        searchKey: 'search', -        alwaysHighlightFirst: true, -        skipSpecialCharacterTest: true, -        data: this.defaultLoadingData, -        callbacks: { -          sorter: this.DefaultOptions.sorter, -          filter: this.DefaultOptions.filter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          matcher: this.DefaultOptions.matcher, -          beforeSave: function(members) { -            return $.map(members, function(m) { -              let title = ''; -              if (m.username == null) { -                return m; -              } -              title = m.name; -              if (m.count) { -                title += " (" + m.count + ")"; -              } +    } +  }, +  setup: function(input) { +    // Add GFM auto-completion to all input fields, that accept GFM input. +    this.input = input || $('.js-gfm-input'); +    this.setupLifecycle(); +  }, +  setupLifecycle() { +    this.input.each((i, input) => { +      const $input = $(input); +      $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input)); +      // This triggers at.js again +      // Needed for slash commands with suffixes (ex: /label ~) +      $input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup')); +    }); +  }, +  setupAtWho: function($input) { +    // Emoji +    $input.atwho({ +      at: ':', +      displayTpl: function(value) { +        return value && value.name ? this.Emoji.templateFunction(value.name) : this.Loading.template; +      }.bind(this), +      insertTpl: ':${name}:', +      skipSpecialCharacterTest: true, +      data: this.defaultLoadingData, +      callbacks: { +        sorter: this.DefaultOptions.sorter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        filter: this.DefaultOptions.filter +      } +    }); +    // Team Members +    $input.atwho({ +      at: '@', +      displayTpl: function(value) { +        return value.username != null ? this.Members.template : this.Loading.template; +      }.bind(this), +      insertTpl: '${atwho-at}${username}', +      searchKey: 'search', +      alwaysHighlightFirst: true, +      skipSpecialCharacterTest: true, +      data: this.defaultLoadingData, +      callbacks: { +        sorter: this.DefaultOptions.sorter, +        filter: this.DefaultOptions.filter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        matcher: this.DefaultOptions.matcher, +        beforeSave: function(members) { +          return $.map(members, function(m) { +            let title = ''; +            if (m.username == null) { +              return m; +            } +            title = m.name; +            if (m.count) { +              title += " (" + m.count + ")"; +            } -              const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase(); -              const imgAvatar = `<img src="${m.avatar_url}" alt="${m.username}" class="avatar avatar-inline center s26"/>`; -              const txtAvatar = `<div class="avatar center avatar-inline s26">${autoCompleteAvatar}</div>`; +            const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase(); +            const imgAvatar = `<img src="${m.avatar_url}" alt="${m.username}" class="avatar avatar-inline center s26"/>`; +            const txtAvatar = `<div class="avatar center avatar-inline s26">${autoCompleteAvatar}</div>`; -              return { -                username: m.username, -                avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, -                title: sanitize(title), -                search: sanitize(m.username + " " + m.name) -              }; -            }); -          } +            return { +              username: m.username, +              avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, +              title: sanitize(title), +              search: sanitize(m.username + " " + m.name) +            }; +          });          } -      }); -      $input.atwho({ -        at: '#', -        alias: 'issues', -        searchKey: 'search', -        displayTpl: function(value) { -          return value.title != null ? this.Issues.template : this.Loading.template; -        }.bind(this), -        data: this.defaultLoadingData, -        insertTpl: '${atwho-at}${id}', -        callbacks: { -          sorter: this.DefaultOptions.sorter, -          filter: this.DefaultOptions.filter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          matcher: this.DefaultOptions.matcher, -          beforeSave: function(issues) { -            return $.map(issues, function(i) { -              if (i.title == null) { -                return i; -              } -              return { -                id: i.iid, -                title: sanitize(i.title), -                search: i.iid + " " + i.title -              }; -            }); -          } +      } +    }); +    $input.atwho({ +      at: '#', +      alias: 'issues', +      searchKey: 'search', +      displayTpl: function(value) { +        return value.title != null ? this.Issues.template : this.Loading.template; +      }.bind(this), +      data: this.defaultLoadingData, +      insertTpl: '${atwho-at}${id}', +      callbacks: { +        sorter: this.DefaultOptions.sorter, +        filter: this.DefaultOptions.filter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        matcher: this.DefaultOptions.matcher, +        beforeSave: function(issues) { +          return $.map(issues, function(i) { +            if (i.title == null) { +              return i; +            } +            return { +              id: i.iid, +              title: sanitize(i.title), +              search: i.iid + " " + i.title +            }; +          });          } -      }); -      $input.atwho({ -        at: '%', -        alias: 'milestones', -        searchKey: 'search', -        insertTpl: '${atwho-at}${title}', -        displayTpl: function(value) { -          return value.title != null ? this.Milestones.template : this.Loading.template; -        }.bind(this), -        data: this.defaultLoadingData, -        callbacks: { -          matcher: this.DefaultOptions.matcher, -          sorter: this.DefaultOptions.sorter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          filter: this.DefaultOptions.filter, -          beforeSave: function(milestones) { -            return $.map(milestones, function(m) { -              if (m.title == null) { -                return m; -              } -              return { -                id: m.iid, -                title: sanitize(m.title), -                search: "" + m.title -              }; -            }); -          } +      } +    }); +    $input.atwho({ +      at: '%', +      alias: 'milestones', +      searchKey: 'search', +      insertTpl: '${atwho-at}${title}', +      displayTpl: function(value) { +        return value.title != null ? this.Milestones.template : this.Loading.template; +      }.bind(this), +      data: this.defaultLoadingData, +      callbacks: { +        matcher: this.DefaultOptions.matcher, +        sorter: this.DefaultOptions.sorter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        filter: this.DefaultOptions.filter, +        beforeSave: function(milestones) { +          return $.map(milestones, function(m) { +            if (m.title == null) { +              return m; +            } +            return { +              id: m.iid, +              title: sanitize(m.title), +              search: "" + m.title +            }; +          });          } -      }); -      $input.atwho({ -        at: '!', -        alias: 'mergerequests', -        searchKey: 'search', -        displayTpl: function(value) { -          return value.title != null ? this.Issues.template : this.Loading.template; -        }.bind(this), -        data: this.defaultLoadingData, -        insertTpl: '${atwho-at}${id}', -        callbacks: { -          sorter: this.DefaultOptions.sorter, -          filter: this.DefaultOptions.filter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          matcher: this.DefaultOptions.matcher, -          beforeSave: function(merges) { -            return $.map(merges, function(m) { -              if (m.title == null) { -                return m; -              } -              return { -                id: m.iid, -                title: sanitize(m.title), -                search: m.iid + " " + m.title -              }; -            }); -          } +      } +    }); +    $input.atwho({ +      at: '!', +      alias: 'mergerequests', +      searchKey: 'search', +      displayTpl: function(value) { +        return value.title != null ? this.Issues.template : this.Loading.template; +      }.bind(this), +      data: this.defaultLoadingData, +      insertTpl: '${atwho-at}${id}', +      callbacks: { +        sorter: this.DefaultOptions.sorter, +        filter: this.DefaultOptions.filter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        matcher: this.DefaultOptions.matcher, +        beforeSave: function(merges) { +          return $.map(merges, function(m) { +            if (m.title == null) { +              return m; +            } +            return { +              id: m.iid, +              title: sanitize(m.title), +              search: m.iid + " " + m.title +            }; +          });          } -      }); -      $input.atwho({ -        at: '~', -        alias: 'labels', -        searchKey: 'search', -        data: this.defaultLoadingData, -        displayTpl: function(value) { -          return this.isLoading(value) ? this.Loading.template : this.Labels.template; -        }.bind(this), -        insertTpl: '${atwho-at}${title}', -        callbacks: { -          matcher: this.DefaultOptions.matcher, -          beforeInsert: this.DefaultOptions.beforeInsert, -          filter: this.DefaultOptions.filter, -          sorter: this.DefaultOptions.sorter, -          beforeSave: function(merges) { -            if (gl.GfmAutoComplete.isLoading(merges)) return merges; -            var sanitizeLabelTitle; -            sanitizeLabelTitle = function(title) { -              if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) { -                return "\"" + (sanitize(title)) + "\""; -              } else { -                return sanitize(title); -              } +      } +    }); +    $input.atwho({ +      at: '~', +      alias: 'labels', +      searchKey: 'search', +      data: this.defaultLoadingData, +      displayTpl: function(value) { +        return this.isLoading(value) ? this.Loading.template : this.Labels.template; +      }.bind(this), +      insertTpl: '${atwho-at}${title}', +      callbacks: { +        matcher: this.DefaultOptions.matcher, +        beforeInsert: this.DefaultOptions.beforeInsert, +        filter: this.DefaultOptions.filter, +        sorter: this.DefaultOptions.sorter, +        beforeSave: function(merges) { +          if (gl.GfmAutoComplete.isLoading(merges)) return merges; +          var sanitizeLabelTitle; +          sanitizeLabelTitle = function(title) { +            if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) { +              return "\"" + (sanitize(title)) + "\""; +            } else { +              return sanitize(title); +            } +          }; +          return $.map(merges, function(m) { +            return { +              title: sanitize(m.title), +              color: m.color, +              search: "" + m.title              }; -            return $.map(merges, function(m) { -              return { -                title: sanitize(m.title), -                color: m.color, -                search: "" + m.title -              }; -            }); -          } +          });          } -      }); -      // We don't instantiate the slash commands autocomplete for note and issue/MR edit forms -      $input.filter('[data-supports-slash-commands="true"]').atwho({ -        at: '/', -        alias: 'commands', -        searchKey: 'search', -        skipSpecialCharacterTest: true, -        data: this.defaultLoadingData, -        displayTpl: function(value) { -          if (this.isLoading(value)) return this.Loading.template; -          var tpl = '<li>/${name}'; -          if (value.aliases.length > 0) { -            tpl += ' <small>(or /<%- aliases.join(", /") %>)</small>'; -          } -          if (value.params.length > 0) { -            tpl += ' <small><%- params.join(" ") %></small>'; -          } -          if (value.description !== '') { -            tpl += '<small class="description"><i><%- description %></i></small>'; +      } +    }); +    // We don't instantiate the slash commands autocomplete for note and issue/MR edit forms +    $input.filter('[data-supports-slash-commands="true"]').atwho({ +      at: '/', +      alias: 'commands', +      searchKey: 'search', +      skipSpecialCharacterTest: true, +      data: this.defaultLoadingData, +      displayTpl: function(value) { +        if (this.isLoading(value)) return this.Loading.template; +        var tpl = '<li>/${name}'; +        if (value.aliases.length > 0) { +          tpl += ' <small>(or /<%- aliases.join(", /") %>)</small>'; +        } +        if (value.params.length > 0) { +          tpl += ' <small><%- params.join(" ") %></small>'; +        } +        if (value.description !== '') { +          tpl += '<small class="description"><i><%- description %></i></small>'; +        } +        tpl += '</li>'; +        return _.template(tpl)(value); +      }.bind(this), +      insertTpl: function(value) { +        var tpl = "/${name} "; +        var reference_prefix = null; +        if (value.params.length > 0) { +          reference_prefix = value.params[0][0]; +          if (/^[@%~]/.test(reference_prefix)) { +            tpl += '<%- reference_prefix %>';            } -          tpl += '</li>'; -          return _.template(tpl)(value); -        }.bind(this), -        insertTpl: function(value) { -          var tpl = "/${name} "; -          var reference_prefix = null; -          if (value.params.length > 0) { -            reference_prefix = value.params[0][0]; -            if (/^[@%~]/.test(reference_prefix)) { -              tpl += '<%- reference_prefix %>'; +        } +        return _.template(tpl)({ reference_prefix: reference_prefix }); +      }, +      suffix: '', +      callbacks: { +        sorter: this.DefaultOptions.sorter, +        filter: this.DefaultOptions.filter, +        beforeInsert: this.DefaultOptions.beforeInsert, +        beforeSave: function(commands) { +          if (gl.GfmAutoComplete.isLoading(commands)) return commands; +          return $.map(commands, function(c) { +            var search = c.name; +            if (c.aliases.length > 0) { +              search = search + " " + c.aliases.join(" ");              } -          } -          return _.template(tpl)({ reference_prefix: reference_prefix }); +            return { +              name: c.name, +              aliases: c.aliases, +              params: c.params, +              description: c.description, +              search: search +            }; +          });          }, -        suffix: '', -        callbacks: { -          sorter: this.DefaultOptions.sorter, -          filter: this.DefaultOptions.filter, -          beforeInsert: this.DefaultOptions.beforeInsert, -          beforeSave: function(commands) { -            if (gl.GfmAutoComplete.isLoading(commands)) return commands; -            return $.map(commands, function(c) { -              var search = c.name; -              if (c.aliases.length > 0) { -                search = search + " " + c.aliases.join(" "); -              } -              return { -                name: c.name, -                aliases: c.aliases, -                params: c.params, -                description: c.description, -                search: search -              }; -            }); -          }, -          matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { -            var regexp = /(?:^|\n)\/([A-Za-z_]*)$/gi; -            var match = regexp.exec(subtext); -            if (match) { -              return match[1]; -            } else { -              return null; -            } +        matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { +          var regexp = /(?:^|\n)\/([A-Za-z_]*)$/gi; +          var match = regexp.exec(subtext); +          if (match) { +            return match[1]; +          } else { +            return null;            }          } -      }); -      return; -    }, -    fetchData: function($input, at) { -      if (this.isLoadingData[at]) return; -      this.isLoadingData[at] = true; -      if (this.cachedData[at]) { -        this.loadData($input, at, this.cachedData[at]); -      } else if (this.atTypeMap[at] === 'emojis') { -        this.loadData($input, at, Object.keys(emojiMap).concat(Object.keys(emojiAliases))); -      } else { -        $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => { -          this.loadData($input, at, data); -        }).fail(() => { this.isLoadingData[at] = false; }); -      } -    }, -    loadData: function($input, at, data) { -      this.isLoadingData[at] = false; -      this.cachedData[at] = data; -      $input.atwho('load', at, data); -      // This trigger at.js again -      // otherwise we would be stuck with loading until the user types -      return $input.trigger('keyup'); -    }, -    isLoading(data) { -      var dataToInspect = data; -      if (data && data.length > 0) { -        dataToInspect = data[0];        } - -      var loadingState = this.defaultLoadingData[0]; -      return dataToInspect && -        (dataToInspect === loadingState || dataToInspect.name === loadingState); +    }); +    return; +  }, +  fetchData: function($input, at) { +    if (this.isLoadingData[at]) return; +    this.isLoadingData[at] = true; +    if (this.cachedData[at]) { +      this.loadData($input, at, this.cachedData[at]); +    } else if (this.atTypeMap[at] === 'emojis') { +      this.loadData($input, at, Object.keys(emojiMap).concat(Object.keys(emojiAliases))); +    } else { +      $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => { +        this.loadData($input, at, data); +      }).fail(() => { this.isLoadingData[at] = false; }); +    } +  }, +  loadData: function($input, at, data) { +    this.isLoadingData[at] = false; +    this.cachedData[at] = data; +    $input.atwho('load', at, data); +    // This trigger at.js again +    // otherwise we would be stuck with loading until the user types +    return $input.trigger('keyup'); +  }, +  isLoading(data) { +    var dataToInspect = data; +    if (data && data.length > 0) { +      dataToInspect = data[0];      } -  }; -}).call(window); + +    var loadingState = this.defaultLoadingData[0]; +    return dataToInspect && +      (dataToInspect === loadingState || dataToInspect.name === loadingState); +  } +}; diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 9e6ed06054b..a03f1202a6d 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -1,850 +1,848 @@  /* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, prefer-rest-params, max-len, vars-on-top, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func, no-mixed-operators */  /* global fuzzaldrinPlus */ -(function() { -  var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote, -    bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, -    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; }; - -  GitLabDropdownFilter = (function() { -    var ARROW_KEY_CODES, BLUR_KEYCODES, HAS_VALUE_CLASS; - -    BLUR_KEYCODES = [27, 40]; - -    ARROW_KEY_CODES = [38, 40]; - -    HAS_VALUE_CLASS = "has-value"; - -    function GitLabDropdownFilter(input, options) { -      var $clearButton, $inputContainer, ref, timeout; -      this.input = input; -      this.options = options; -      this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true; -      $inputContainer = this.input.parent(); -      $clearButton = $inputContainer.find('.js-dropdown-input-clear'); -      $clearButton.on('click', (function(_this) { -        // Clear click -        return function(e) { +var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote, +  bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, +  indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; }; + +GitLabDropdownFilter = (function() { +  var ARROW_KEY_CODES, BLUR_KEYCODES, HAS_VALUE_CLASS; + +  BLUR_KEYCODES = [27, 40]; + +  ARROW_KEY_CODES = [38, 40]; + +  HAS_VALUE_CLASS = "has-value"; + +  function GitLabDropdownFilter(input, options) { +    var $clearButton, $inputContainer, ref, timeout; +    this.input = input; +    this.options = options; +    this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true; +    $inputContainer = this.input.parent(); +    $clearButton = $inputContainer.find('.js-dropdown-input-clear'); +    $clearButton.on('click', (function(_this) { +      // Clear click +      return function(e) { +        e.preventDefault(); +        e.stopPropagation(); +        return _this.input.val('').trigger('input').focus(); +      }; +    })(this)); +    // Key events +    timeout = ""; +    this.input +      .on('keydown', function (e) { +        var keyCode = e.which; +        if (keyCode === 13 && !options.elIsInput) {            e.preventDefault(); -          e.stopPropagation(); -          return _this.input.val('').trigger('input').focus(); -        }; -      })(this)); -      // Key events -      timeout = ""; -      this.input -        .on('keydown', function (e) { -          var keyCode = e.which; -          if (keyCode === 13 && !options.elIsInput) { -            e.preventDefault(); -          } -        }) -        .on('input', function() { -          if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { -            $inputContainer.addClass(HAS_VALUE_CLASS); -          } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { -            $inputContainer.removeClass(HAS_VALUE_CLASS); -          } -          // Only filter asynchronously only if option remote is set -          if (this.options.remote) { -            clearTimeout(timeout); -            return timeout = setTimeout(function() { -              $inputContainer.parent().addClass('is-loading'); - -              return this.options.query(this.input.val(), function(data) { -                $inputContainer.parent().removeClass('is-loading'); -                return this.options.callback(data); -              }.bind(this)); -            }.bind(this), 250); -          } else { -            return this.filter(this.input.val()); -          } -        }.bind(this)); -    } +        } +      }) +      .on('input', function() { +        if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { +          $inputContainer.addClass(HAS_VALUE_CLASS); +        } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { +          $inputContainer.removeClass(HAS_VALUE_CLASS); +        } +        // Only filter asynchronously only if option remote is set +        if (this.options.remote) { +          clearTimeout(timeout); +          return timeout = setTimeout(function() { +            $inputContainer.parent().addClass('is-loading'); + +            return this.options.query(this.input.val(), function(data) { +              $inputContainer.parent().removeClass('is-loading'); +              return this.options.callback(data); +            }.bind(this)); +          }.bind(this), 250); +        } else { +          return this.filter(this.input.val()); +        } +      }.bind(this)); +  } -    GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) { -      return BLUR_KEYCODES.indexOf(keyCode) !== -1; -    }; +  GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) { +    return BLUR_KEYCODES.indexOf(keyCode) !== -1; +  }; -    GitLabDropdownFilter.prototype.filter = function(search_text) { -      var data, elements, group, key, results, tmp; -      if (this.options.onFilter) { -        this.options.onFilter(search_text); -      } -      data = this.options.data(); -      if ((data != null) && !this.options.filterByText) { -        results = data; -        if (search_text !== '') { -          // When data is an array of objects therefore [object Array] e.g. -          // [ -          //   { prop: 'foo' }, -          //   { prop: 'baz' } -          // ] -          if (_.isArray(data)) { -            results = fuzzaldrinPlus.filter(data, search_text, { -              key: this.options.keys -            }); -          } else { -            // If data is grouped therefore an [object Object]. e.g. -            // { -            //   groupName1: [ -            //     { prop: 'foo' }, -            //     { prop: 'baz' } -            //   ], -            //   groupName2: [ -            //     { prop: 'abc' }, -            //     { prop: 'def' } -            //   ] -            // } -            if (gl.utils.isObject(data)) { -              results = {}; -              for (key in data) { -                group = data[key]; -                tmp = fuzzaldrinPlus.filter(group, search_text, { -                  key: this.options.keys +  GitLabDropdownFilter.prototype.filter = function(search_text) { +    var data, elements, group, key, results, tmp; +    if (this.options.onFilter) { +      this.options.onFilter(search_text); +    } +    data = this.options.data(); +    if ((data != null) && !this.options.filterByText) { +      results = data; +      if (search_text !== '') { +        // When data is an array of objects therefore [object Array] e.g. +        // [ +        //   { prop: 'foo' }, +        //   { prop: 'baz' } +        // ] +        if (_.isArray(data)) { +          results = fuzzaldrinPlus.filter(data, search_text, { +            key: this.options.keys +          }); +        } else { +          // If data is grouped therefore an [object Object]. e.g. +          // { +          //   groupName1: [ +          //     { prop: 'foo' }, +          //     { prop: 'baz' } +          //   ], +          //   groupName2: [ +          //     { prop: 'abc' }, +          //     { prop: 'def' } +          //   ] +          // } +          if (gl.utils.isObject(data)) { +            results = {}; +            for (key in data) { +              group = data[key]; +              tmp = fuzzaldrinPlus.filter(group, search_text, { +                key: this.options.keys +              }); +              if (tmp.length) { +                results[key] = tmp.map(function(item) { +                  return item;                  }); -                if (tmp.length) { -                  results[key] = tmp.map(function(item) { -                    return item; -                  }); -                }                }              }            }          } -        return this.options.callback(results); -      } else { -        elements = this.options.elements(); -        if (search_text) { -          return elements.each(function() { -            var $el, matches; -            $el = $(this); -            matches = fuzzaldrinPlus.match($el.text().trim(), search_text); -            if (!$el.is('.dropdown-header')) { -              if (matches.length) { -                return $el.show().removeClass('option-hidden'); -              } else { -                return $el.hide().addClass('option-hidden'); -              } +      } +      return this.options.callback(results); +    } else { +      elements = this.options.elements(); +      if (search_text) { +        return elements.each(function() { +          var $el, matches; +          $el = $(this); +          matches = fuzzaldrinPlus.match($el.text().trim(), search_text); +          if (!$el.is('.dropdown-header')) { +            if (matches.length) { +              return $el.show().removeClass('option-hidden'); +            } else { +              return $el.hide().addClass('option-hidden');              } -          }); -        } else { -          return elements.show().removeClass('option-hidden'); -        } +          } +        }); +      } else { +        return elements.show().removeClass('option-hidden');        } -    }; - -    return GitLabDropdownFilter; -  })(); +    } +  }; -  GitLabDropdownRemote = (function() { -    function GitLabDropdownRemote(dataEndpoint, options) { -      this.dataEndpoint = dataEndpoint; -      this.options = options; +  return GitLabDropdownFilter; +})(); + +GitLabDropdownRemote = (function() { +  function GitLabDropdownRemote(dataEndpoint, options) { +    this.dataEndpoint = dataEndpoint; +    this.options = options; +  } + +  GitLabDropdownRemote.prototype.execute = function() { +    if (typeof this.dataEndpoint === "string") { +      return this.fetchData(); +    } else if (typeof this.dataEndpoint === "function") { +      if (this.options.beforeSend) { +        this.options.beforeSend(); +      } +      return this.dataEndpoint("", (function(_this) { +        // Fetch the data by calling the data funcfion +        return function(data) { +          if (_this.options.success) { +            _this.options.success(data); +          } +          if (_this.options.beforeSend) { +            return _this.options.beforeSend(); +          } +        }; +      })(this));      } +  }; -    GitLabDropdownRemote.prototype.execute = function() { -      if (typeof this.dataEndpoint === "string") { -        return this.fetchData(); -      } else if (typeof this.dataEndpoint === "function") { -        if (this.options.beforeSend) { -          this.options.beforeSend(); -        } -        return this.dataEndpoint("", (function(_this) { -          // Fetch the data by calling the data funcfion -          return function(data) { -            if (_this.options.success) { -              _this.options.success(data); -            } -            if (_this.options.beforeSend) { -              return _this.options.beforeSend(); -            } -          }; -        })(this)); -      } -    }; +  GitLabDropdownRemote.prototype.fetchData = function() { +    return $.ajax({ +      url: this.dataEndpoint, +      dataType: this.options.dataType, +      beforeSend: (function(_this) { +        return function() { +          if (_this.options.beforeSend) { +            return _this.options.beforeSend(); +          } +        }; +      })(this), +      success: (function(_this) { +        return function(data) { +          if (_this.options.success) { +            return _this.options.success(data); +          } +        }; +      })(this) +    }); +  // Fetch the data through ajax if the data is a string +  }; -    GitLabDropdownRemote.prototype.fetchData = function() { -      return $.ajax({ -        url: this.dataEndpoint, -        dataType: this.options.dataType, -        beforeSend: (function(_this) { -          return function() { -            if (_this.options.beforeSend) { -              return _this.options.beforeSend(); -            } -          }; -        })(this), -        success: (function(_this) { -          return function(data) { -            if (_this.options.success) { -              return _this.options.success(data); -            } -          }; -        })(this) -      }); -    // Fetch the data through ajax if the data is a string -    }; +  return GitLabDropdownRemote; +})(); -    return GitLabDropdownRemote; -  })(); +GitLabDropdown = (function() { +  var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, CURSOR_SELECT_SCROLL_PADDING, currentIndex; -  GitLabDropdown = (function() { -    var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, CURSOR_SELECT_SCROLL_PADDING, currentIndex; +  LOADING_CLASS = "is-loading"; -    LOADING_CLASS = "is-loading"; +  PAGE_TWO_CLASS = "is-page-two"; -    PAGE_TWO_CLASS = "is-page-two"; +  ACTIVE_CLASS = "is-active"; -    ACTIVE_CLASS = "is-active"; +  INDETERMINATE_CLASS = "is-indeterminate"; -    INDETERMINATE_CLASS = "is-indeterminate"; +  currentIndex = -1; -    currentIndex = -1; +  NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; -    NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; - -    SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)"; - -    CURSOR_SELECT_SCROLL_PADDING = 5; - -    FILTER_INPUT = '.dropdown-input .dropdown-input-field'; - -    function GitLabDropdown(el1, options) { -      var searchFields, selector, self; -      this.el = el1; -      this.options = options; -      this.updateLabel = bind(this.updateLabel, this); -      this.hidden = bind(this.hidden, this); -      this.opened = bind(this.opened, this); -      this.shouldPropagate = bind(this.shouldPropagate, this); -      self = this; -      selector = $(this.el).data("target"); -      this.dropdown = selector != null ? $(selector) : $(this.el).parent(); -      // Set Defaults -      this.filterInput = this.options.filterInput || this.getElement(FILTER_INPUT); -      this.highlight = !!this.options.highlight; -      this.filterInputBlur = this.options.filterInputBlur != null -        ? this.options.filterInputBlur -        : true; -      // If no input is passed create a default one -      self = this; -      // If selector was passed -      if (_.isString(this.filterInput)) { -        this.filterInput = this.getElement(this.filterInput); -      } -      searchFields = this.options.search ? this.options.search.fields : []; -      if (this.options.data) { -        // If we provided data -        // data could be an array of objects or a group of arrays -        if (_.isObject(this.options.data) && !_.isFunction(this.options.data)) { -          this.fullData = this.options.data; -          currentIndex = -1; -          this.parseData(this.options.data); -          this.focusTextInput(); -        } else { -          this.remote = new GitLabDropdownRemote(this.options.data, { -            dataType: this.options.dataType, -            beforeSend: this.toggleLoading.bind(this), -            success: (function(_this) { -              return function(data) { -                _this.fullData = data; -                _this.parseData(_this.fullData); -                _this.focusTextInput(); -                if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') { -                  return _this.filter.input.trigger('input'); -                } -              }; -            // Remote data -            })(this) -          }); -        } -      } -      // Init filterable -      if (this.options.filterable) { -        this.filter = new GitLabDropdownFilter(this.filterInput, { -          elIsInput: $(this.el).is('input'), -          filterInputBlur: this.filterInputBlur, -          filterByText: this.options.filterByText, -          onFilter: this.options.onFilter, -          remote: this.options.filterRemote, -          query: this.options.data, -          keys: searchFields, -          elements: (function(_this) { -            return function() { -              selector = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ')'; -              if (_this.dropdown.find('.dropdown-toggle-page').length) { -                selector = ".dropdown-page-one " + selector; -              } -              return $(selector); -            }; -          })(this), -          data: (function(_this) { -            return function() { -              return _this.fullData; -            }; -          })(this), -          callback: (function(_this) { +  SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)"; + +  CURSOR_SELECT_SCROLL_PADDING = 5; + +  FILTER_INPUT = '.dropdown-input .dropdown-input-field'; + +  function GitLabDropdown(el1, options) { +    var searchFields, selector, self; +    this.el = el1; +    this.options = options; +    this.updateLabel = bind(this.updateLabel, this); +    this.hidden = bind(this.hidden, this); +    this.opened = bind(this.opened, this); +    this.shouldPropagate = bind(this.shouldPropagate, this); +    self = this; +    selector = $(this.el).data("target"); +    this.dropdown = selector != null ? $(selector) : $(this.el).parent(); +    // Set Defaults +    this.filterInput = this.options.filterInput || this.getElement(FILTER_INPUT); +    this.highlight = !!this.options.highlight; +    this.filterInputBlur = this.options.filterInputBlur != null +      ? this.options.filterInputBlur +      : true; +    // If no input is passed create a default one +    self = this; +    // If selector was passed +    if (_.isString(this.filterInput)) { +      this.filterInput = this.getElement(this.filterInput); +    } +    searchFields = this.options.search ? this.options.search.fields : []; +    if (this.options.data) { +      // If we provided data +      // data could be an array of objects or a group of arrays +      if (_.isObject(this.options.data) && !_.isFunction(this.options.data)) { +        this.fullData = this.options.data; +        currentIndex = -1; +        this.parseData(this.options.data); +        this.focusTextInput(); +      } else { +        this.remote = new GitLabDropdownRemote(this.options.data, { +          dataType: this.options.dataType, +          beforeSend: this.toggleLoading.bind(this), +          success: (function(_this) {              return function(data) { -              _this.parseData(data); -              if (_this.filterInput.val() !== '') { -                selector = SELECTABLE_CLASSES; -                if (_this.dropdown.find('.dropdown-toggle-page').length) { -                  selector = ".dropdown-page-one " + selector; -                } -                if ($(_this.el).is('input')) { -                  currentIndex = -1; -                } else { -                  $(selector, _this.dropdown).first().find('a').addClass('is-focused'); -                  currentIndex = 0; -                } +              _this.fullData = data; +              _this.parseData(_this.fullData); +              _this.focusTextInput(); +              if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') { +                return _this.filter.input.trigger('input');                }              }; +          // Remote data            })(this)          });        } -      // Event listeners -      this.dropdown.on("shown.bs.dropdown", this.opened); -      this.dropdown.on("hidden.bs.dropdown", this.hidden); -      $(this.el).on("update.label", this.updateLabel); -      this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate); -      this.dropdown.on('keyup', (function(_this) { -        return function(e) { -          // Escape key -          if (e.which === 27) { -            return $('.dropdown-menu-close', _this.dropdown).trigger('click'); -          } -        }; -      })(this)); -      this.dropdown.on('blur', 'a', (function(_this) { -        return function(e) { -          var $dropdownMenu, $relatedTarget; -          if (e.relatedTarget != null) { -            $relatedTarget = $(e.relatedTarget); -            $dropdownMenu = $relatedTarget.closest('.dropdown-menu'); -            if ($dropdownMenu.length === 0) { -              return _this.dropdown.removeClass('open'); +    } +    // Init filterable +    if (this.options.filterable) { +      this.filter = new GitLabDropdownFilter(this.filterInput, { +        elIsInput: $(this.el).is('input'), +        filterInputBlur: this.filterInputBlur, +        filterByText: this.options.filterByText, +        onFilter: this.options.onFilter, +        remote: this.options.filterRemote, +        query: this.options.data, +        keys: searchFields, +        elements: (function(_this) { +          return function() { +            selector = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ')'; +            if (_this.dropdown.find('.dropdown-toggle-page').length) { +              selector = ".dropdown-page-one " + selector; +            } +            return $(selector); +          }; +        })(this), +        data: (function(_this) { +          return function() { +            return _this.fullData; +          }; +        })(this), +        callback: (function(_this) { +          return function(data) { +            _this.parseData(data); +            if (_this.filterInput.val() !== '') { +              selector = SELECTABLE_CLASSES; +              if (_this.dropdown.find('.dropdown-toggle-page').length) { +                selector = ".dropdown-page-one " + selector; +              } +              if ($(_this.el).is('input')) { +                currentIndex = -1; +              } else { +                $(selector, _this.dropdown).first().find('a').addClass('is-focused'); +                currentIndex = 0; +              }              } +          }; +        })(this) +      }); +    } +    // Event listeners +    this.dropdown.on("shown.bs.dropdown", this.opened); +    this.dropdown.on("hidden.bs.dropdown", this.hidden); +    $(this.el).on("update.label", this.updateLabel); +    this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate); +    this.dropdown.on('keyup', (function(_this) { +      return function(e) { +        // Escape key +        if (e.which === 27) { +          return $('.dropdown-menu-close', _this.dropdown).trigger('click'); +        } +      }; +    })(this)); +    this.dropdown.on('blur', 'a', (function(_this) { +      return function(e) { +        var $dropdownMenu, $relatedTarget; +        if (e.relatedTarget != null) { +          $relatedTarget = $(e.relatedTarget); +          $dropdownMenu = $relatedTarget.closest('.dropdown-menu'); +          if ($dropdownMenu.length === 0) { +            return _this.dropdown.removeClass('open');            } +        } +      }; +    })(this)); +    if (this.dropdown.find(".dropdown-toggle-page").length) { +      this.dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on("click", (function(_this) { +        return function(e) { +          e.preventDefault(); +          e.stopPropagation(); +          return _this.togglePage();          };        })(this)); +    } +    if (this.options.selectable) { +      selector = ".dropdown-content a";        if (this.dropdown.find(".dropdown-toggle-page").length) { -        this.dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on("click", (function(_this) { -          return function(e) { -            e.preventDefault(); -            e.stopPropagation(); -            return _this.togglePage(); -          }; -        })(this)); -      } -      if (this.options.selectable) { -        selector = ".dropdown-content a"; -        if (this.dropdown.find(".dropdown-toggle-page").length) { -          selector = ".dropdown-page-one .dropdown-content a"; +        selector = ".dropdown-page-one .dropdown-content a"; +      } +      this.dropdown.on("click", selector, function(e) { +        var $el, selected, selectedObj, isMarking; +        $el = $(this); +        selected = self.rowClicked($el); +        selectedObj = selected ? selected[0] : null; +        isMarking = selected ? selected[1] : null; +        if (self.options.clicked) { +          self.options.clicked(selectedObj, $el, e, isMarking);          } -        this.dropdown.on("click", selector, function(e) { -          var $el, selected, selectedObj, isMarking; -          $el = $(this); -          selected = self.rowClicked($el); -          selectedObj = selected ? selected[0] : null; -          isMarking = selected ? selected[1] : null; -          if (self.options.clicked) { -            self.options.clicked(selectedObj, $el, e, isMarking); -          } -          // Update label right after all modifications in dropdown has been done -          if (self.options.toggleLabel) { -            self.updateLabel(selectedObj, $el, self); -          } +        // Update label right after all modifications in dropdown has been done +        if (self.options.toggleLabel) { +          self.updateLabel(selectedObj, $el, self); +        } -          $el.trigger('blur'); -        }); -      } +        $el.trigger('blur'); +      });      } +  } -    // Finds an element inside wrapper element -    GitLabDropdown.prototype.getElement = function(selector) { -      return this.dropdown.find(selector); -    }; +  // Finds an element inside wrapper element +  GitLabDropdown.prototype.getElement = function(selector) { +    return this.dropdown.find(selector); +  }; -    GitLabDropdown.prototype.toggleLoading = function() { -      return $('.dropdown-menu', this.dropdown).toggleClass(LOADING_CLASS); -    }; +  GitLabDropdown.prototype.toggleLoading = function() { +    return $('.dropdown-menu', this.dropdown).toggleClass(LOADING_CLASS); +  }; -    GitLabDropdown.prototype.togglePage = function() { -      var menu; -      menu = $('.dropdown-menu', this.dropdown); -      if (menu.hasClass(PAGE_TWO_CLASS)) { -        if (this.remote) { -          this.remote.execute(); -        } -      } -      menu.toggleClass(PAGE_TWO_CLASS); -      // Focus first visible input on active page -      return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus(); -    }; - -    GitLabDropdown.prototype.parseData = function(data) { -      var full_html, groupData, html, name; -      this.renderedData = data; -      if (this.options.filterable && data.length === 0) { -        // render no matching results -        html = [this.noResults()]; -      } else { -        // Handle array groups -        if (gl.utils.isObject(data)) { -          html = []; -          for (name in data) { -            groupData = data[name]; -            html.push(this.renderItem({ -              header: name -            // Add header for each group -            }, name)); -            this.renderData(groupData, name).map(function(item) { -              return html.push(item); -            }); -          } -        } else { -          // Render each row -          html = this.renderData(data); -        } -      } -      // Render the full menu -      full_html = this.renderMenu(html); -      return this.appendMenu(full_html); -    }; - -    GitLabDropdown.prototype.renderData = function(data, group) { -      if (group == null) { -        group = false; +  GitLabDropdown.prototype.togglePage = function() { +    var menu; +    menu = $('.dropdown-menu', this.dropdown); +    if (menu.hasClass(PAGE_TWO_CLASS)) { +      if (this.remote) { +        this.remote.execute();        } -      return data.map((function(_this) { -        return function(obj, index) { -          return _this.renderItem(obj, group, index); -        }; -      })(this)); -    }; - -    GitLabDropdown.prototype.shouldPropagate = function(e) { -      var $target; -      if (this.options.multiSelect) { -        $target = $(e.target); -        if ($target && !$target.hasClass('dropdown-menu-close') && -                       !$target.hasClass('dropdown-menu-close-icon') && -                       !$target.data('is-link')) { -          e.stopPropagation(); -          return false; -        } else { -          return true; +    } +    menu.toggleClass(PAGE_TWO_CLASS); +    // Focus first visible input on active page +    return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus(); +  }; + +  GitLabDropdown.prototype.parseData = function(data) { +    var full_html, groupData, html, name; +    this.renderedData = data; +    if (this.options.filterable && data.length === 0) { +      // render no matching results +      html = [this.noResults()]; +    } else { +      // Handle array groups +      if (gl.utils.isObject(data)) { +        html = []; +        for (name in data) { +          groupData = data[name]; +          html.push(this.renderItem({ +            header: name +          // Add header for each group +          }, name)); +          this.renderData(groupData, name).map(function(item) { +            return html.push(item); +          });          } +      } else { +        // Render each row +        html = this.renderData(data);        } -    }; +    } +    // Render the full menu +    full_html = this.renderMenu(html); +    return this.appendMenu(full_html); +  }; -    GitLabDropdown.prototype.opened = function(e) { -      var contentHtml; -      this.resetRows(); -      this.addArrowKeyEvent(); +  GitLabDropdown.prototype.renderData = function(data, group) { +    if (group == null) { +      group = false; +    } +    return data.map((function(_this) { +      return function(obj, index) { +        return _this.renderItem(obj, group, index); +      }; +    })(this)); +  }; -      // Makes indeterminate items effective -      if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) { -        this.parseData(this.fullData); -      } -      contentHtml = $('.dropdown-content', this.dropdown).html(); -      if (this.remote && contentHtml === "") { -        this.remote.execute(); +  GitLabDropdown.prototype.shouldPropagate = function(e) { +    var $target; +    if (this.options.multiSelect) { +      $target = $(e.target); +      if ($target && !$target.hasClass('dropdown-menu-close') && +                     !$target.hasClass('dropdown-menu-close-icon') && +                     !$target.data('is-link')) { +        e.stopPropagation(); +        return false;        } else { -        this.focusTextInput(); +        return true;        } +    } +  }; -      if (this.options.showMenuAbove) { -        this.positionMenuAbove(); -      } +  GitLabDropdown.prototype.opened = function(e) { +    var contentHtml; +    this.resetRows(); +    this.addArrowKeyEvent(); -      if (this.options.opened) { -        this.options.opened.call(this, e); -      } +    // Makes indeterminate items effective +    if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) { +      this.parseData(this.fullData); +    } +    contentHtml = $('.dropdown-content', this.dropdown).html(); +    if (this.remote && contentHtml === "") { +      this.remote.execute(); +    } else { +      this.focusTextInput(); +    } + +    if (this.options.showMenuAbove) { +      this.positionMenuAbove(); +    } -      return this.dropdown.trigger('shown.gl.dropdown'); -    }; +    if (this.options.opened) { +      this.options.opened.call(this, e); +    } -    GitLabDropdown.prototype.positionMenuAbove = function() { -      var $button = $(this.el); -      var $menu = this.dropdown.find('.dropdown-menu'); +    return this.dropdown.trigger('shown.gl.dropdown'); +  }; -      $menu.css('top', ($button.height() + $menu.height()) * -1); -    }; +  GitLabDropdown.prototype.positionMenuAbove = function() { +    var $button = $(this.el); +    var $menu = this.dropdown.find('.dropdown-menu'); -    GitLabDropdown.prototype.hidden = function(e) { -      var $input; -      this.resetRows(); -      this.removeArrayKeyEvent(); -      $input = this.dropdown.find(".dropdown-input-field"); -      if (this.options.filterable) { -        $input.blur(); -      } -      if (this.dropdown.find(".dropdown-toggle-page").length) { -        $('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS); -      } -      if (this.options.hidden) { -        this.options.hidden.call(this, e); -      } -      return this.dropdown.trigger('hidden.gl.dropdown'); -    }; +    $menu.css('top', ($button.height() + $menu.height()) * -1); +  }; -    // Render the full menu -    GitLabDropdown.prototype.renderMenu = function(html) { -      if (this.options.renderMenu) { -        return this.options.renderMenu(html); -      } else { -        var ul = document.createElement('ul'); +  GitLabDropdown.prototype.hidden = function(e) { +    var $input; +    this.resetRows(); +    this.removeArrayKeyEvent(); +    $input = this.dropdown.find(".dropdown-input-field"); +    if (this.options.filterable) { +      $input.blur(); +    } +    if (this.dropdown.find(".dropdown-toggle-page").length) { +      $('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS); +    } +    if (this.options.hidden) { +      this.options.hidden.call(this, e); +    } +    return this.dropdown.trigger('hidden.gl.dropdown'); +  }; -        for (var i = 0; i < html.length; i += 1) { -          var el = html[i]; +  // Render the full menu +  GitLabDropdown.prototype.renderMenu = function(html) { +    if (this.options.renderMenu) { +      return this.options.renderMenu(html); +    } else { +      var ul = document.createElement('ul'); -          if (el instanceof jQuery) { -            el = el.get(0); -          } +      for (var i = 0; i < html.length; i += 1) { +        var el = html[i]; -          if (typeof el === 'string') { -            ul.innerHTML += el; -          } else { -            ul.appendChild(el); -          } +        if (el instanceof jQuery) { +          el = el.get(0);          } -        return ul; +        if (typeof el === 'string') { +          ul.innerHTML += el; +        } else { +          ul.appendChild(el); +        }        } -    }; -    // Append the menu into the dropdown -    GitLabDropdown.prototype.appendMenu = function(html) { -      return this.clearMenu().append(html); -    }; +      return ul; +    } +  }; + +  // Append the menu into the dropdown +  GitLabDropdown.prototype.appendMenu = function(html) { +    return this.clearMenu().append(html); +  }; -    GitLabDropdown.prototype.clearMenu = function() { -      var selector; -      selector = '.dropdown-content'; -      if (this.dropdown.find(".dropdown-toggle-page").length) { -        selector = ".dropdown-page-one .dropdown-content"; -      } +  GitLabDropdown.prototype.clearMenu = function() { +    var selector; +    selector = '.dropdown-content'; +    if (this.dropdown.find(".dropdown-toggle-page").length) { +      selector = ".dropdown-page-one .dropdown-content"; +    } -      return $(selector, this.dropdown).empty(); -    }; +    return $(selector, this.dropdown).empty(); +  }; -    GitLabDropdown.prototype.renderItem = function(data, group, index) { -      var field, fieldName, html, selected, text, url, value; -      if (group == null) { -        group = false; +  GitLabDropdown.prototype.renderItem = function(data, group, index) { +    var field, fieldName, html, selected, text, url, value; +    if (group == null) { +      group = false; +    } +    if (index == null) { +      // Render the row +      index = false; +    } +    html = document.createElement('li'); +    if (data === 'divider' || data === 'separator') { +      html.className = data; +      return html; +    } +    // Header +    if (data.header != null) { +      html.className = 'dropdown-header'; +      html.innerHTML = data.header; +      return html; +    } +    if (this.options.renderRow) { +      // Call the render function +      html = this.options.renderRow.call(this.options, data, this); +    } else { +      if (!selected) { +        value = this.options.id ? this.options.id(data) : data.id; +        fieldName = this.options.fieldName; + +        if (value) { value = value.toString().replace(/'/g, '\\\''); } + +        field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); +        if (field.length) { +          selected = true; +        }        } -      if (index == null) { -        // Render the row -        index = false; +      // Set URL +      if (this.options.url != null) { +        url = this.options.url(data); +      } else { +        url = data.url != null ? data.url : '#';        } -      html = document.createElement('li'); -      if (data === 'divider' || data === 'separator') { -        html.className = data; -        return html; +      // Set Text +      if (this.options.text != null) { +        text = this.options.text(data); +      } else { +        text = data.text != null ? data.text : '';        } -      // Header -      if (data.header != null) { -        html.className = 'dropdown-header'; -        html.innerHTML = data.header; -        return html; +      if (this.highlight) { +        text = this.highlightTextMatches(text, this.filterInput.val());        } -      if (this.options.renderRow) { -        // Call the render function -        html = this.options.renderRow.call(this.options, data, this); -      } else { -        if (!selected) { -          value = this.options.id ? this.options.id(data) : data.id; -          fieldName = this.options.fieldName; - -          if (value) { value = value.toString().replace(/'/g, '\\\''); } - -          field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); -          if (field.length) { -            selected = true; -          } -        } -        // Set URL -        if (this.options.url != null) { -          url = this.options.url(data); -        } else { -          url = data.url != null ? data.url : '#'; -        } -        // Set Text -        if (this.options.text != null) { -          text = this.options.text(data); -        } else { -          text = data.text != null ? data.text : ''; -        } -        if (this.highlight) { -          text = this.highlightTextMatches(text, this.filterInput.val()); -        } -        // Create the list item & the link -        var link = document.createElement('a'); - -        link.href = url; -        link.innerHTML = text; +      // Create the list item & the link +      var link = document.createElement('a'); -        if (selected) { -          link.className = 'is-active'; -        } - -        if (group) { -          link.dataset.group = group; -          link.dataset.index = index; -        } +      link.href = url; +      link.innerHTML = text; -        html.appendChild(link); +      if (selected) { +        link.className = 'is-active';        } -      return html; -    }; - -    GitLabDropdown.prototype.highlightTextMatches = function(text, term) { -      var occurrences; -      occurrences = fuzzaldrinPlus.match(text, term); -      return text.split('').map(function(character, i) { -        if (indexOf.call(occurrences, i) !== -1) { -          return "<b>" + character + "</b>"; -        } else { -          return character; -        } -      }).join(''); -    }; - -    GitLabDropdown.prototype.noResults = function() { -      var html; -      return html = "<li class='dropdown-menu-empty-link'> <a href='#' class='is-focused'> No matching results. </a> </li>"; -    }; - -    GitLabDropdown.prototype.rowClicked = function(el) { -      var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value, isMarking; - -      fieldName = this.options.fieldName; -      isInput = $(this.el).is('input'); -      if (this.renderedData) { -        groupName = el.data('group'); -        if (groupName) { -          selectedIndex = el.data('index'); -          selectedObject = this.renderedData[groupName][selectedIndex]; -        } else { -          selectedIndex = el.closest('li').index(); -          selectedObject = this.renderedData[selectedIndex]; -        } + +      if (group) { +        link.dataset.group = group; +        link.dataset.index = index;        } -      if (this.options.vue) { -        if (el.hasClass(ACTIVE_CLASS)) { -          el.removeClass(ACTIVE_CLASS); -        } else { -          el.addClass(ACTIVE_CLASS); -        } +      html.appendChild(link); +    } +    return html; +  }; -        return [selectedObject]; +  GitLabDropdown.prototype.highlightTextMatches = function(text, term) { +    var occurrences; +    occurrences = fuzzaldrinPlus.match(text, term); +    return text.split('').map(function(character, i) { +      if (indexOf.call(occurrences, i) !== -1) { +        return "<b>" + character + "</b>"; +      } else { +        return character;        } +    }).join(''); +  }; -      field = []; -      value = this.options.id -        ? this.options.id(selectedObject, el) -        : selectedObject.id; -      if (isInput) { -        field = $(this.el); -      } else if (value) { -        field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']"); -      } +  GitLabDropdown.prototype.noResults = function() { +    var html; +    return html = "<li class='dropdown-menu-empty-link'> <a href='#' class='is-focused'> No matching results. </a> </li>"; +  }; + +  GitLabDropdown.prototype.rowClicked = function(el) { +    var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value, isMarking; -      if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) { -        return; +    fieldName = this.options.fieldName; +    isInput = $(this.el).is('input'); +    if (this.renderedData) { +      groupName = el.data('group'); +      if (groupName) { +        selectedIndex = el.data('index'); +        selectedObject = this.renderedData[groupName][selectedIndex]; +      } else { +        selectedIndex = el.closest('li').index(); +        selectedObject = this.renderedData[selectedIndex];        } +    } +    if (this.options.vue) {        if (el.hasClass(ACTIVE_CLASS)) { -        isMarking = false;          el.removeClass(ACTIVE_CLASS); -        if (field && field.length) { -          this.clearField(field, isInput); -        } -      } else if (el.hasClass(INDETERMINATE_CLASS)) { -        isMarking = true; -        el.addClass(ACTIVE_CLASS); -        el.removeClass(INDETERMINATE_CLASS); -        if (field && field.length && value == null) { -          this.clearField(field, isInput); -        } -        if ((!field || !field.length) && fieldName) { -          this.addInput(fieldName, value, selectedObject); -        }        } else { -        isMarking = true; -        if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) { -          this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS); -          if (!isInput) { -            this.dropdown.parent().find("input[name='" + fieldName + "']").remove(); -          } -        } -        if (field && field.length && value == null) { -          this.clearField(field, isInput); -        } -        // Toggle active class for the tick mark          el.addClass(ACTIVE_CLASS); -        if (value != null) { -          if ((!field || !field.length) && fieldName) { -            this.addInput(fieldName, value, selectedObject); -          } else if (field && field.length) { -            field.val(value).trigger('change'); -          } -        }        } -      return [selectedObject, isMarking]; -    }; +      return [selectedObject]; +    } -    GitLabDropdown.prototype.focusTextInput = function() { -      if (this.options.filterable) { this.filterInput.focus(); } -    }; +    field = []; +    value = this.options.id +      ? this.options.id(selectedObject, el) +      : selectedObject.id; +    if (isInput) { +      field = $(this.el); +    } else if (value) { +      field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']"); +    } -    GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) { -      var $input; -      // Create hidden input for form -      $input = $('<input>').attr('type', 'hidden').attr('name', fieldName).val(value); -      if (this.options.inputId != null) { -        $input.attr('id', this.options.inputId); -      } -      return this.dropdown.before($input); -    }; - -    GitLabDropdown.prototype.selectRowAtIndex = function(index) { -      var $el, selector; -      // If we pass an option index -      if (typeof index !== "undefined") { -        selector = SELECTABLE_CLASSES + ":eq(" + index + ") a"; -      } else { -        selector = ".dropdown-content .is-focused"; +    if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) { +      return; +    } + +    if (el.hasClass(ACTIVE_CLASS)) { +      isMarking = false; +      el.removeClass(ACTIVE_CLASS); +      if (field && field.length) { +        this.clearField(field, isInput); +      } +    } else if (el.hasClass(INDETERMINATE_CLASS)) { +      isMarking = true; +      el.addClass(ACTIVE_CLASS); +      el.removeClass(INDETERMINATE_CLASS); +      if (field && field.length && value == null) { +        this.clearField(field, isInput); +      } +      if ((!field || !field.length) && fieldName) { +        this.addInput(fieldName, value, selectedObject); +      } +    } else { +      isMarking = true; +      if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) { +        this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS); +        if (!isInput) { +          this.dropdown.parent().find("input[name='" + fieldName + "']").remove(); +        }        } -      if (this.dropdown.find(".dropdown-toggle-page").length) { -        selector = ".dropdown-page-one " + selector; +      if (field && field.length && value == null) { +        this.clearField(field, isInput);        } -      // simulate a click on the first link -      $el = $(selector, this.dropdown); -      if ($el.length) { -        var href = $el.attr('href'); -        if (href && href !== '#') { -          gl.utils.visitUrl(href); -        } else { -          $el.first().trigger('click'); +      // Toggle active class for the tick mark +      el.addClass(ACTIVE_CLASS); +      if (value != null) { +        if ((!field || !field.length) && fieldName) { +          this.addInput(fieldName, value, selectedObject); +        } else if (field && field.length) { +          field.val(value).trigger('change');          }        } -    }; +    } -    GitLabDropdown.prototype.addArrowKeyEvent = function() { -      var $input, ARROW_KEY_CODES, selector; -      ARROW_KEY_CODES = [38, 40]; -      $input = this.dropdown.find(".dropdown-input-field"); -      selector = SELECTABLE_CLASSES; -      if (this.dropdown.find(".dropdown-toggle-page").length) { -        selector = ".dropdown-page-one " + selector; +    return [selectedObject, isMarking]; +  }; + +  GitLabDropdown.prototype.focusTextInput = function() { +    if (this.options.filterable) { this.filterInput.focus(); } +  }; + +  GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) { +    var $input; +    // Create hidden input for form +    $input = $('<input>').attr('type', 'hidden').attr('name', fieldName).val(value); +    if (this.options.inputId != null) { +      $input.attr('id', this.options.inputId); +    } +    return this.dropdown.before($input); +  }; + +  GitLabDropdown.prototype.selectRowAtIndex = function(index) { +    var $el, selector; +    // If we pass an option index +    if (typeof index !== "undefined") { +      selector = SELECTABLE_CLASSES + ":eq(" + index + ") a"; +    } else { +      selector = ".dropdown-content .is-focused"; +    } +    if (this.dropdown.find(".dropdown-toggle-page").length) { +      selector = ".dropdown-page-one " + selector; +    } +    // simulate a click on the first link +    $el = $(selector, this.dropdown); +    if ($el.length) { +      var href = $el.attr('href'); +      if (href && href !== '#') { +        gl.utils.visitUrl(href); +      } else { +        $el.first().trigger('click');        } -      return $('body').on('keydown', (function(_this) { -        return function(e) { -          var $listItems, PREV_INDEX, currentKeyCode; -          currentKeyCode = e.which; -          if (ARROW_KEY_CODES.indexOf(currentKeyCode) !== -1) { -            e.preventDefault(); -            e.stopImmediatePropagation(); -            PREV_INDEX = currentIndex; -            $listItems = $(selector, _this.dropdown); -            // if @options.filterable -            //   $input.blur() -            if (currentKeyCode === 40) { -              // Move down -              if (currentIndex < ($listItems.length - 1)) { -                currentIndex += 1; -              } -            } else if (currentKeyCode === 38) { -              // Move up -              if (currentIndex > 0) { -                currentIndex -= 1; -              } +    } +  }; + +  GitLabDropdown.prototype.addArrowKeyEvent = function() { +    var $input, ARROW_KEY_CODES, selector; +    ARROW_KEY_CODES = [38, 40]; +    $input = this.dropdown.find(".dropdown-input-field"); +    selector = SELECTABLE_CLASSES; +    if (this.dropdown.find(".dropdown-toggle-page").length) { +      selector = ".dropdown-page-one " + selector; +    } +    return $('body').on('keydown', (function(_this) { +      return function(e) { +        var $listItems, PREV_INDEX, currentKeyCode; +        currentKeyCode = e.which; +        if (ARROW_KEY_CODES.indexOf(currentKeyCode) !== -1) { +          e.preventDefault(); +          e.stopImmediatePropagation(); +          PREV_INDEX = currentIndex; +          $listItems = $(selector, _this.dropdown); +          // if @options.filterable +          //   $input.blur() +          if (currentKeyCode === 40) { +            // Move down +            if (currentIndex < ($listItems.length - 1)) { +              currentIndex += 1;              } -            if (currentIndex !== PREV_INDEX) { -              _this.highlightRowAtIndex($listItems, currentIndex); +          } else if (currentKeyCode === 38) { +            // Move up +            if (currentIndex > 0) { +              currentIndex -= 1;              } -            return false;            } -          if (currentKeyCode === 13 && currentIndex !== -1) { -            e.preventDefault(); -            _this.selectRowAtIndex(); +          if (currentIndex !== PREV_INDEX) { +            _this.highlightRowAtIndex($listItems, currentIndex);            } -        }; -      })(this)); -    }; - -    GitLabDropdown.prototype.removeArrayKeyEvent = function() { -      return $('body').off('keydown'); -    }; - -    GitLabDropdown.prototype.resetRows = function resetRows() { -      currentIndex = -1; -      $('.is-focused', this.dropdown).removeClass('is-focused'); -    }; - -    GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) { -      var $dropdownContent, $listItem, dropdownContentBottom, dropdownContentHeight, dropdownContentTop, dropdownScrollTop, listItemBottom, listItemHeight, listItemTop; -      // Remove the class for the previously focused row -      $('.is-focused', this.dropdown).removeClass('is-focused'); -      // Update the class for the row at the specific index -      $listItem = $listItems.eq(index); -      $listItem.find('a:first-child').addClass("is-focused"); -      // Dropdown content scroll area -      $dropdownContent = $listItem.closest('.dropdown-content'); -      dropdownScrollTop = $dropdownContent.scrollTop(); -      dropdownContentHeight = $dropdownContent.outerHeight(); -      dropdownContentTop = $dropdownContent.prop('offsetTop'); -      dropdownContentBottom = dropdownContentTop + dropdownContentHeight; -      // Get the offset bottom of the list item -      listItemHeight = $listItem.outerHeight(); -      listItemTop = $listItem.prop('offsetTop'); -      listItemBottom = listItemTop + listItemHeight; -      if (!index) { -        // Scroll the dropdown content to the top -        $dropdownContent.scrollTop(0); -      } else if (index === ($listItems.length - 1)) { -        // Scroll the dropdown content to the bottom -        $dropdownContent.scrollTop($dropdownContent.prop('scrollHeight')); -      } else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) { -        // Scroll the dropdown content down -        $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING); -      } else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) { -        // Scroll the dropdown content up -        return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING); -      } -    }; +          return false; +        } +        if (currentKeyCode === 13 && currentIndex !== -1) { +          e.preventDefault(); +          _this.selectRowAtIndex(); +        } +      }; +    })(this)); +  }; -    GitLabDropdown.prototype.updateLabel = function(selected, el, instance) { -      if (selected == null) { -        selected = null; -      } -      if (el == null) { -        el = null; -      } -      if (instance == null) { -        instance = null; -      } -      return $(this.el).find(".dropdown-toggle-text").text(this.options.toggleLabel(selected, el, instance)); -    }; +  GitLabDropdown.prototype.removeArrayKeyEvent = function() { +    return $('body').off('keydown'); +  }; -    GitLabDropdown.prototype.clearField = function(field, isInput) { -      return isInput ? field.val('') : field.remove(); -    }; +  GitLabDropdown.prototype.resetRows = function resetRows() { +    currentIndex = -1; +    $('.is-focused', this.dropdown).removeClass('is-focused'); +  }; -    return GitLabDropdown; -  })(); +  GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) { +    var $dropdownContent, $listItem, dropdownContentBottom, dropdownContentHeight, dropdownContentTop, dropdownScrollTop, listItemBottom, listItemHeight, listItemTop; +    // Remove the class for the previously focused row +    $('.is-focused', this.dropdown).removeClass('is-focused'); +    // Update the class for the row at the specific index +    $listItem = $listItems.eq(index); +    $listItem.find('a:first-child').addClass("is-focused"); +    // Dropdown content scroll area +    $dropdownContent = $listItem.closest('.dropdown-content'); +    dropdownScrollTop = $dropdownContent.scrollTop(); +    dropdownContentHeight = $dropdownContent.outerHeight(); +    dropdownContentTop = $dropdownContent.prop('offsetTop'); +    dropdownContentBottom = dropdownContentTop + dropdownContentHeight; +    // Get the offset bottom of the list item +    listItemHeight = $listItem.outerHeight(); +    listItemTop = $listItem.prop('offsetTop'); +    listItemBottom = listItemTop + listItemHeight; +    if (!index) { +      // Scroll the dropdown content to the top +      $dropdownContent.scrollTop(0); +    } else if (index === ($listItems.length - 1)) { +      // Scroll the dropdown content to the bottom +      $dropdownContent.scrollTop($dropdownContent.prop('scrollHeight')); +    } else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) { +      // Scroll the dropdown content down +      $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING); +    } else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) { +      // Scroll the dropdown content up +      return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING); +    } +  }; -  $.fn.glDropdown = function(opts) { -    return this.each(function() { -      if (!$.data(this, 'glDropdown')) { -        return $.data(this, 'glDropdown', new GitLabDropdown(this, opts)); -      } -    }); +  GitLabDropdown.prototype.updateLabel = function(selected, el, instance) { +    if (selected == null) { +      selected = null; +    } +    if (el == null) { +      el = null; +    } +    if (instance == null) { +      instance = null; +    } +    return $(this.el).find(".dropdown-toggle-text").text(this.options.toggleLabel(selected, el, instance)); +  }; + +  GitLabDropdown.prototype.clearField = function(field, isInput) { +    return isInput ? field.val('') : field.remove();    }; -}).call(window); + +  return GitLabDropdown; +})(); + +$.fn.glDropdown = function(opts) { +  return this.each(function() { +    if (!$.data(this, 'glDropdown')) { +      return $.data(this, 'glDropdown', new GitLabDropdown(this, opts)); +    } +  }); +}; diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js index f7cbecc0385..76de249ac3b 100644 --- a/app/assets/javascripts/gl_field_error.js +++ b/app/assets/javascripts/gl_field_error.js @@ -1,164 +1,162 @@ -/* eslint-disable no-param-reassign */ -((global) => { -  /* -   * This class overrides the browser's validation error bubbles, displaying custom -   * error messages for invalid fields instead. To begin validating any form, add the -   * class `gl-show-field-errors` to the form element, and ensure error messages are -   * declared in each inputs' `title` attribute. If no title is declared for an invalid -   * field the user attempts to submit, "This field is required." will be shown by default. -   * -   * Opt not to validate certain fields by adding the class `gl-field-error-ignore` to the input. -   * -   * Set a custom error anchor for error message to be injected after with the -   * class `gl-field-error-anchor` -   * -   * Examples: -   * -   * Basic: -   * -   * <form class='gl-show-field-errors'> -   *  <input type='text' name='username' title='Username is required.'/> -   * </form> -   * -   * Ignore specific inputs (e.g. UsernameValidator): -   * -   * <form class='gl-show-field-errors'> -   *   <div class="form-group> -   *     <input type='text' class='gl-field-errors-ignore' pattern='[a-zA-Z0-9-_]+'/> -   *   </div> -   *   <div class="form-group"> -   *      <input type='text' name='username' title='Username is required.'/> -   *    </div> -   * </form> -   * -   * Custom Error Anchor (allows error message to be injected after specified element): -   * -   * <form class='gl-show-field-errors'> -   *  <div class="form-group gl-field-error-anchor"> -   *    <input type='text' name='username' title='Username is required.'/> -   *    // Error message typically injected here -   *  </div> -   *  // Error message now injected here -   * </form> -   * -    * */ - -  /* -    * Regex Patterns in use: -    * -    * Only alphanumeric: : "[a-zA-Z0-9]+" -    * No special characters : "[a-zA-Z0-9-_]+", -    * -    * */ - -  const errorMessageClass = 'gl-field-error'; -  const inputErrorClass = 'gl-field-error-outline'; -  const errorAnchorSelector = '.gl-field-error-anchor'; -  const ignoreInputSelector = '.gl-field-error-ignore'; - -  class GlFieldError { -    constructor({ input, formErrors }) { -      this.inputElement = $(input); -      this.inputDomElement = this.inputElement.get(0); -      this.form = formErrors; -      this.errorMessage = this.inputElement.attr('title') || 'This field is required.'; -      this.fieldErrorElement = $(`<p class='${errorMessageClass} hide'>${this.errorMessage}</p>`); - -      this.state = { -        valid: false, -        empty: true, -      }; - -      this.initFieldValidation(); -    } +/** + * This class overrides the browser's validation error bubbles, displaying custom + * error messages for invalid fields instead. To begin validating any form, add the + * class `gl-show-field-errors` to the form element, and ensure error messages are + * declared in each inputs' `title` attribute. If no title is declared for an invalid + * field the user attempts to submit, "This field is required." will be shown by default. + * + * Opt not to validate certain fields by adding the class `gl-field-error-ignore` to the input. + * + * Set a custom error anchor for error message to be injected after with the + * class `gl-field-error-anchor` + * + * Examples: + * + * Basic: + * + * <form class='gl-show-field-errors'> + *  <input type='text' name='username' title='Username is required.'/> + * </form> + * + * Ignore specific inputs (e.g. UsernameValidator): + * + * <form class='gl-show-field-errors'> + *   <div class="form-group> + *     <input type='text' class='gl-field-errors-ignore' pattern='[a-zA-Z0-9-_]+'/> + *   </div> + *   <div class="form-group"> + *      <input type='text' name='username' title='Username is required.'/> + *    </div> + * </form> + * + * Custom Error Anchor (allows error message to be injected after specified element): + * + * <form class='gl-show-field-errors'> + *  <div class="form-group gl-field-error-anchor"> + *    <input type='text' name='username' title='Username is required.'/> + *    // Error message typically injected here + *  </div> + *  // Error message now injected here + * </form> + * + */ + +/** + * Regex Patterns in use: + * + * Only alphanumeric: : "[a-zA-Z0-9]+" + * No special characters : "[a-zA-Z0-9-_]+", + * + */ + +const errorMessageClass = 'gl-field-error'; +const inputErrorClass = 'gl-field-error-outline'; +const errorAnchorSelector = '.gl-field-error-anchor'; +const ignoreInputSelector = '.gl-field-error-ignore'; + +class GlFieldError { +  constructor({ input, formErrors }) { +    this.inputElement = $(input); +    this.inputDomElement = this.inputElement.get(0); +    this.form = formErrors; +    this.errorMessage = this.inputElement.attr('title') || 'This field is required.'; +    this.fieldErrorElement = $(`<p class='${errorMessageClass} hide'>${this.errorMessage}</p>`); + +    this.state = { +      valid: false, +      empty: true, +    }; + +    this.initFieldValidation(); +  } -    initFieldValidation() { -      const customErrorAnchor = this.inputElement.parents(errorAnchorSelector); -      const errorAnchor = customErrorAnchor.length ? customErrorAnchor : this.inputElement; +  initFieldValidation() { +    const customErrorAnchor = this.inputElement.parents(errorAnchorSelector); +    const errorAnchor = customErrorAnchor.length ? customErrorAnchor : this.inputElement; -      // hidden when injected into DOM -      errorAnchor.after(this.fieldErrorElement); -      this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this)); -      this.scopedSiblings = this.safelySelectSiblings(); -    } +    // hidden when injected into DOM +    errorAnchor.after(this.fieldErrorElement); +    this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this)); +    this.scopedSiblings = this.safelySelectSiblings(); +  } -    safelySelectSiblings() { -      // Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled -      const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreInputSelector})`); -      const parentContainer = this.inputElement.parent('.form-group'); +  safelySelectSiblings() { +    // Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled +    const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreInputSelector})`); +    const parentContainer = this.inputElement.parent('.form-group'); -      // Only select siblings when they're scoped within a form-group with one input -      const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1; +    // Only select siblings when they're scoped within a form-group with one input +    const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1; -      return safelyScoped ? unignoredSiblings : this.fieldErrorElement; -    } +    return safelyScoped ? unignoredSiblings : this.fieldErrorElement; +  } -    renderValidity() { -      this.renderClear(); +  renderValidity() { +    this.renderClear(); -      if (this.state.valid) { -        this.renderValid(); -      } else if (this.state.empty) { -        this.renderEmpty(); -      } else if (!this.state.valid) { -        this.renderInvalid(); -      } +    if (this.state.valid) { +      this.renderValid(); +    } else if (this.state.empty) { +      this.renderEmpty(); +    } else if (!this.state.valid) { +      this.renderInvalid();      } +  } -    handleInvalidSubmit(event) { -      event.preventDefault(); -      const currentValue = this.accessCurrentValue(); -      this.state.valid = false; -      this.state.empty = currentValue === ''; - -      this.renderValidity(); -      this.form.focusOnFirstInvalid.apply(this.form); -      // For UX, wait til after first invalid submission to check each keyup -      this.inputElement.off('keyup.fieldValidator') -        .on('keyup.fieldValidator', this.updateValidity.bind(this)); -    } +  handleInvalidSubmit(event) { +    event.preventDefault(); +    const currentValue = this.accessCurrentValue(); +    this.state.valid = false; +    this.state.empty = currentValue === ''; + +    this.renderValidity(); +    this.form.focusOnFirstInvalid.apply(this.form); +    // For UX, wait til after first invalid submission to check each keyup +    this.inputElement.off('keyup.fieldValidator') +      .on('keyup.fieldValidator', this.updateValidity.bind(this)); +  } -    /* Get or set current input value */ -    accessCurrentValue(newVal) { -      return newVal ? this.inputElement.val(newVal) : this.inputElement.val(); -    } +  /* Get or set current input value */ +  accessCurrentValue(newVal) { +    return newVal ? this.inputElement.val(newVal) : this.inputElement.val(); +  } -    getInputValidity() { -      return this.inputDomElement.validity.valid; -    } +  getInputValidity() { +    return this.inputDomElement.validity.valid; +  } -    updateValidity() { -      const inputVal = this.accessCurrentValue(); -      this.state.empty = !inputVal.length; -      this.state.valid = this.getInputValidity(); -      this.renderValidity(); -    } +  updateValidity() { +    const inputVal = this.accessCurrentValue(); +    this.state.empty = !inputVal.length; +    this.state.valid = this.getInputValidity(); +    this.renderValidity(); +  } -    renderValid() { -      return this.renderClear(); -    } +  renderValid() { +    return this.renderClear(); +  } -    renderEmpty() { -      return this.renderInvalid(); -    } +  renderEmpty() { +    return this.renderInvalid(); +  } -    renderInvalid() { -      this.inputElement.addClass(inputErrorClass); -      this.scopedSiblings.hide(); -      return this.fieldErrorElement.show(); -    } +  renderInvalid() { +    this.inputElement.addClass(inputErrorClass); +    this.scopedSiblings.hide(); +    return this.fieldErrorElement.show(); +  } -    renderClear() { -      const inputVal = this.accessCurrentValue(); -      if (!inputVal.split(' ').length) { -        const trimmedInput = inputVal.trim(); -        this.accessCurrentValue(trimmedInput); -      } -      this.inputElement.removeClass(inputErrorClass); -      this.scopedSiblings.hide(); -      this.fieldErrorElement.hide(); +  renderClear() { +    const inputVal = this.accessCurrentValue(); +    if (!inputVal.split(' ').length) { +      const trimmedInput = inputVal.trim(); +      this.accessCurrentValue(trimmedInput);      } +    this.inputElement.removeClass(inputErrorClass); +    this.scopedSiblings.hide(); +    this.fieldErrorElement.hide();    } +} -  global.GlFieldError = GlFieldError; -})(window.gl || (window.gl = {})); +window.gl = window.gl || {}; +window.gl.GlFieldError = GlFieldError; diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js index e9add115429..636258ec555 100644 --- a/app/assets/javascripts/gl_field_errors.js +++ b/app/assets/javascripts/gl_field_errors.js @@ -2,47 +2,46 @@  require('./gl_field_error'); -((global) => { -  const customValidationFlag = 'gl-field-error-ignore'; - -  class GlFieldErrors { -    constructor(form) { -      this.form = $(form); -      this.state = { -        inputs: [], -        valid: false -      }; -      this.initValidators(); -    } +const customValidationFlag = 'gl-field-error-ignore'; + +class GlFieldErrors { +  constructor(form) { +    this.form = $(form); +    this.state = { +      inputs: [], +      valid: false +    }; +    this.initValidators(); +  } -    initValidators () { -      // register selectors here as needed -      const validateSelectors = [':text', ':password', '[type=email]'] -        .map((selector) => `input${selector}`).join(','); +  initValidators () { +    // register selectors here as needed +    const validateSelectors = [':text', ':password', '[type=email]'] +      .map((selector) => `input${selector}`).join(','); -      this.state.inputs = this.form.find(validateSelectors).toArray() -        .filter((input) => !input.classList.contains(customValidationFlag)) -        .map((input) => new global.GlFieldError({ input, formErrors: this })); +    this.state.inputs = this.form.find(validateSelectors).toArray() +      .filter((input) => !input.classList.contains(customValidationFlag)) +      .map((input) => new window.gl.GlFieldError({ input, formErrors: this })); -      this.form.on('submit', this.catchInvalidFormSubmit); -    } +    this.form.on('submit', this.catchInvalidFormSubmit); +  } -    /* Neccessary to prevent intercept and override invalid form submit -     * because Safari & iOS quietly allow form submission when form is invalid -     * and prevents disabling of invalid submit button by application.js */ +  /* Neccessary to prevent intercept and override invalid form submit +   * because Safari & iOS quietly allow form submission when form is invalid +   * and prevents disabling of invalid submit button by application.js */ -    catchInvalidFormSubmit (event) { -      if (!event.currentTarget.checkValidity()) { -        event.preventDefault(); -        event.stopPropagation(); -      } +  catchInvalidFormSubmit (event) { +    if (!event.currentTarget.checkValidity()) { +      event.preventDefault(); +      event.stopPropagation();      } +  } -    focusOnFirstInvalid () { -      const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0]; -      firstInvalid.inputElement.focus(); -    } +  focusOnFirstInvalid () { +    const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0]; +    firstInvalid.inputElement.focus();    } +} -  global.GlFieldErrors = GlFieldErrors; -})(window.gl || (window.gl = {})); +window.gl = window.gl || {}; +window.gl.GlFieldErrors = GlFieldErrors; diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 0b446ff364a..e7c98e16581 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -3,90 +3,88 @@  /* global DropzoneInput */  /* global autosize */ -(() => { -  const global = window.gl || (window.gl = {}); +window.gl = window.gl || {}; -  function GLForm(form) { -    this.form = form; -    this.textarea = this.form.find('textarea.js-gfm-input'); -    // Before we start, we should clean up any previous data for this form -    this.destroy(); -    // Setup the form -    this.setupForm(); -    this.form.data('gl-form', this); -  } +function GLForm(form) { +  this.form = form; +  this.textarea = this.form.find('textarea.js-gfm-input'); +  // Before we start, we should clean up any previous data for this form +  this.destroy(); +  // Setup the form +  this.setupForm(); +  this.form.data('gl-form', this); +} -  GLForm.prototype.destroy = function() { -    // Clean form listeners -    this.clearEventListeners(); -    return this.form.data('gl-form', null); -  }; +GLForm.prototype.destroy = function() { +  // Clean form listeners +  this.clearEventListeners(); +  return this.form.data('gl-form', null); +}; -  GLForm.prototype.setupForm = function() { -    var isNewForm; -    isNewForm = this.form.is(':not(.gfm-form)'); -    this.form.removeClass('js-new-note-form'); -    if (isNewForm) { -      this.form.find('.div-dropzone').remove(); -      this.form.addClass('gfm-form'); -      // remove notify commit author checkbox for non-commit notes -      gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); -      gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input')); -      new DropzoneInput(this.form); -      autosize(this.textarea); -      // form and textarea event listeners -      this.addEventListeners(); -    } -    gl.text.init(this.form); -    // hide discard button -    this.form.find('.js-note-discard').hide(); -    this.form.show(); -    if (this.isAutosizeable) this.setupAutosize(); -  }; +GLForm.prototype.setupForm = function() { +  var isNewForm; +  isNewForm = this.form.is(':not(.gfm-form)'); +  this.form.removeClass('js-new-note-form'); +  if (isNewForm) { +    this.form.find('.div-dropzone').remove(); +    this.form.addClass('gfm-form'); +    // remove notify commit author checkbox for non-commit notes +    gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); +    gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input')); +    new DropzoneInput(this.form); +    autosize(this.textarea); +    // form and textarea event listeners +    this.addEventListeners(); +  } +  gl.text.init(this.form); +  // hide discard button +  this.form.find('.js-note-discard').hide(); +  this.form.show(); +  if (this.isAutosizeable) this.setupAutosize(); +}; -  GLForm.prototype.setupAutosize = function () { -    this.textarea.off('autosize:resized') -      .on('autosize:resized', this.setHeightData.bind(this)); +GLForm.prototype.setupAutosize = function () { +  this.textarea.off('autosize:resized') +    .on('autosize:resized', this.setHeightData.bind(this)); -    this.textarea.off('mouseup.autosize') -      .on('mouseup.autosize', this.destroyAutosize.bind(this)); +  this.textarea.off('mouseup.autosize') +    .on('mouseup.autosize', this.destroyAutosize.bind(this)); -    setTimeout(() => { -      autosize(this.textarea); -      this.textarea.css('resize', 'vertical'); -    }, 0); -  }; +  setTimeout(() => { +    autosize(this.textarea); +    this.textarea.css('resize', 'vertical'); +  }, 0); +}; -  GLForm.prototype.setHeightData = function () { -    this.textarea.data('height', this.textarea.outerHeight()); -  }; +GLForm.prototype.setHeightData = function () { +  this.textarea.data('height', this.textarea.outerHeight()); +}; -  GLForm.prototype.destroyAutosize = function () { -    const outerHeight = this.textarea.outerHeight(); +GLForm.prototype.destroyAutosize = function () { +  const outerHeight = this.textarea.outerHeight(); -    if (this.textarea.data('height') === outerHeight) return; +  if (this.textarea.data('height') === outerHeight) return; -    autosize.destroy(this.textarea); +  autosize.destroy(this.textarea); -    this.textarea.data('height', outerHeight); -    this.textarea.outerHeight(outerHeight); -    this.textarea.css('max-height', window.outerHeight); -  }; +  this.textarea.data('height', outerHeight); +  this.textarea.outerHeight(outerHeight); +  this.textarea.css('max-height', window.outerHeight); +}; -  GLForm.prototype.clearEventListeners = function() { -    this.textarea.off('focus'); -    this.textarea.off('blur'); -    return gl.text.removeListeners(this.form); -  }; +GLForm.prototype.clearEventListeners = function() { +  this.textarea.off('focus'); +  this.textarea.off('blur'); +  return gl.text.removeListeners(this.form); +}; -  GLForm.prototype.addEventListeners = function() { -    this.textarea.on('focus', function() { -      return $(this).closest('.md-area').addClass('is-focused'); -    }); -    return this.textarea.on('blur', function() { -      return $(this).closest('.md-area').removeClass('is-focused'); -    }); -  }; +GLForm.prototype.addEventListeners = function() { +  this.textarea.on('focus', function() { +    return $(this).closest('.md-area').addClass('is-focused'); +  }); +  return this.textarea.on('blur', function() { +    return $(this).closest('.md-area').removeClass('is-focused'); +  }); +}; -  global.GLForm = GLForm; -})(); +window.gl.GLForm = GLForm; diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js index c5cb273c5b2..f03b47b1c1d 100644 --- a/app/assets/javascripts/group_avatar.js +++ b/app/assets/javascripts/group_avatar.js @@ -1,20 +1,19 @@  /* 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 */ -(function() { -  this.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); -      }); -    } -    return GroupAvatar; -  })(); -}).call(window); +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); +    }); +  } + +  return GroupAvatar; +})(); diff --git a/app/assets/javascripts/group_label_subscription.js b/app/assets/javascripts/group_label_subscription.js index 15e695e81cf..7dc9ce898e8 100644 --- a/app/assets/javascripts/group_label_subscription.js +++ b/app/assets/javascripts/group_label_subscription.js @@ -1,53 +1,52 @@  /* eslint-disable func-names, object-shorthand, comma-dangle, wrap-iife, space-before-function-paren, no-param-reassign, max-len */ -(function(global) { -  class GroupLabelSubscription { -    constructor(container) { -      const $container = $(container); -      this.$dropdown = $container.find('.dropdown'); -      this.$subscribeButtons = $container.find('.js-subscribe-button'); -      this.$unsubscribeButtons = $container.find('.js-unsubscribe-button'); - -      this.$subscribeButtons.on('click', this.subscribe.bind(this)); -      this.$unsubscribeButtons.on('click', this.unsubscribe.bind(this)); -    } - -    unsubscribe(event) { -      event.preventDefault(); - -      const url = this.$unsubscribeButtons.attr('data-url'); - -      $.ajax({ -        type: 'POST', -        url: url -      }).done(() => { -        this.toggleSubscriptionButtons(); -        this.$unsubscribeButtons.removeAttr('data-url'); -      }); -    } - -    subscribe(event) { -      event.preventDefault(); - -      const $btn = $(event.currentTarget); -      const url = $btn.attr('data-url'); - -      this.$unsubscribeButtons.attr('data-url', url); - -      $.ajax({ -        type: 'POST', -        url: url -      }).done(() => { -        this.toggleSubscriptionButtons(); -      }); -    } - -    toggleSubscriptionButtons() { -      this.$dropdown.toggleClass('hidden'); -      this.$subscribeButtons.toggleClass('hidden'); -      this.$unsubscribeButtons.toggleClass('hidden'); -    } +class GroupLabelSubscription { +  constructor(container) { +    const $container = $(container); +    this.$dropdown = $container.find('.dropdown'); +    this.$subscribeButtons = $container.find('.js-subscribe-button'); +    this.$unsubscribeButtons = $container.find('.js-unsubscribe-button'); + +    this.$subscribeButtons.on('click', this.subscribe.bind(this)); +    this.$unsubscribeButtons.on('click', this.unsubscribe.bind(this));    } -  global.GroupLabelSubscription = GroupLabelSubscription; -})(window.gl || (window.gl = {})); +  unsubscribe(event) { +    event.preventDefault(); + +    const url = this.$unsubscribeButtons.attr('data-url'); + +    $.ajax({ +      type: 'POST', +      url: url +    }).done(() => { +      this.toggleSubscriptionButtons(); +      this.$unsubscribeButtons.removeAttr('data-url'); +    }); +  } + +  subscribe(event) { +    event.preventDefault(); + +    const $btn = $(event.currentTarget); +    const url = $btn.attr('data-url'); + +    this.$unsubscribeButtons.attr('data-url', url); + +    $.ajax({ +      type: 'POST', +      url: url +    }).done(() => { +      this.toggleSubscriptionButtons(); +    }); +  } + +  toggleSubscriptionButtons() { +    this.$dropdown.toggleClass('hidden'); +    this.$subscribeButtons.toggleClass('hidden'); +    this.$unsubscribeButtons.toggleClass('hidden'); +  } +} + +window.gl = window.gl || {}; +window.gl.GroupLabelSubscription = GroupLabelSubscription; diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index 6b937e7fa0f..e5dfa30edab 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -1,71 +1,69 @@  /* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, camelcase, one-var-declaration-per-line, quotes, object-shorthand, prefer-arrow-callback, comma-dangle, consistent-return, yoda, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, max-len */  /* global Api */ -(function() { -  var slice = [].slice; +var slice = [].slice; -  this.GroupsSelect = (function() { -    function GroupsSelect() { -      $('.ajax-groups-select').each((function(_this) { -        return function(i, select) { -          var all_available, skip_groups; -          all_available = $(select).data('all-available'); -          skip_groups = $(select).data('skip-groups') || []; -          return $(select).select2({ -            placeholder: "Search for a group", -            multiple: $(select).hasClass('multiselect'), -            minimumInputLength: 0, -            query: function(query) { -              var options = { all_available: all_available, skip_groups: skip_groups }; -              return Api.groups(query.term, options, function(groups) { -                var data; -                data = { -                  results: groups -                }; -                return query.callback(data); -              }); -            }, -            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 _this.formatResult.apply(_this, args); -            }, -            formatSelection: function() { -              var args; -              args = 1 <= arguments.length ? slice.call(arguments, 0) : []; -              return _this.formatSelection.apply(_this, args); -            }, -            dropdownCssClass: "ajax-groups-dropdown", -            // we do not want to escape markup since we are displaying html in results -            escapeMarkup: function(m) { -              return m; +window.GroupsSelect = (function() { +  function GroupsSelect() { +    $('.ajax-groups-select').each((function(_this) { +      return function(i, select) { +        var all_available, skip_groups; +        all_available = $(select).data('all-available'); +        skip_groups = $(select).data('skip-groups') || []; +        return $(select).select2({ +          placeholder: "Search for a group", +          multiple: $(select).hasClass('multiselect'), +          minimumInputLength: 0, +          query: function(query) { +            var options = { all_available: all_available, skip_groups: skip_groups }; +            return Api.groups(query.term, options, function(groups) { +              var data; +              data = { +                results: groups +              }; +              return query.callback(data); +            }); +          }, +          initSelection: function(element, callback) { +            var id; +            id = $(element).val(); +            if (id !== "") { +              return Api.group(id, callback);              } -          }); -        }; -      })(this)); -    } +          }, +          formatResult: function() { +            var args; +            args = 1 <= arguments.length ? slice.call(arguments, 0) : []; +            return _this.formatResult.apply(_this, args); +          }, +          formatSelection: function() { +            var args; +            args = 1 <= arguments.length ? slice.call(arguments, 0) : []; +            return _this.formatSelection.apply(_this, args); +          }, +          dropdownCssClass: "ajax-groups-dropdown", +          // we do not want to escape markup since we are displaying html in results +          escapeMarkup: function(m) { +            return m; +          } +        }); +      }; +    })(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; +  }; -    return GroupsSelect; -  })(); -}).call(window); +  return GroupsSelect; +})(); diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index a853c3aeb1f..34f44dad7a5 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -1,8 +1,7 @@ -/* eslint-disable wrap-iife, func-names, space-before-function-paren, prefer-arrow-callback, no-var, max-len */ -(function() { -  $(document).on('todo:toggle', function(e, count) { -    var $todoPendingCount = $('.todos-pending-count'); -    $todoPendingCount.text(gl.text.highCountTrim(count)); -    $todoPendingCount.toggleClass('hidden', count === 0); -  }); -})(); +/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var */ + +$(document).on('todo:toggle', function(e, count) { +  var $todoPendingCount = $('.todos-pending-count'); +  $todoPendingCount.text(gl.text.highCountTrim(count)); +  $todoPendingCount.toggleClass('hidden', count === 0); +}); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index cf3e4ee77b6..81d5748191d 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -198,189 +198,187 @@ import './visibility_select';  import './wikis';  import './zen_mode'; -(function () { -  document.addEventListener('beforeunload', function () { -    // Unbind scroll events -    $(document).off('scroll'); -    // Close any open tooltips -    $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); -  }); - -  window.addEventListener('hashchange', gl.utils.handleLocationHash); -  window.addEventListener('load', function onLoad() { -    window.removeEventListener('load', onLoad, false); -    gl.utils.handleLocationHash(); -  }, false); +document.addEventListener('beforeunload', function () { +  // Unbind scroll events +  $(document).off('scroll'); +  // Close any open tooltips +  $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); +}); -  $(function () { -    var $body = $('body'); -    var $document = $(document); -    var $window = $(window); -    var $sidebarGutterToggle = $('.js-sidebar-toggle'); -    var $flash = $('.flash-container'); -    var bootstrapBreakpoint = bp.getBreakpointSize(); -    var fitSidebarForSize; +window.addEventListener('hashchange', gl.utils.handleLocationHash); +window.addEventListener('load', function onLoad() { +  window.removeEventListener('load', onLoad, false); +  gl.utils.handleLocationHash(); +}, false); -    // Set the default path for all cookies to GitLab's root directory -    Cookies.defaults.path = gon.relative_url_root || '/'; +$(function () { +  var $body = $('body'); +  var $document = $(document); +  var $window = $(window); +  var $sidebarGutterToggle = $('.js-sidebar-toggle'); +  var $flash = $('.flash-container'); +  var bootstrapBreakpoint = bp.getBreakpointSize(); +  var fitSidebarForSize; -    // `hashchange` is not triggered when link target is already in window.location -    $body.on('click', 'a[href^="#"]', function() { -      var href = this.getAttribute('href'); -      if (href.substr(1) === gl.utils.getLocationHash()) { -        setTimeout(gl.utils.handleLocationHash, 1); -      } -    }); +  // Set the default path for all cookies to GitLab's root directory +  Cookies.defaults.path = gon.relative_url_root || '/'; -    // prevent default action for disabled buttons -    $('.btn').click(function(e) { -      if ($(this).hasClass('disabled')) { -        e.preventDefault(); -        e.stopImmediatePropagation(); -        return false; -      } -    }); +  // `hashchange` is not triggered when link target is already in window.location +  $body.on('click', 'a[href^="#"]', function() { +    var href = this.getAttribute('href'); +    if (href.substr(1) === gl.utils.getLocationHash()) { +      setTimeout(gl.utils.handleLocationHash, 1); +    } +  }); -    $('.js-select-on-focus').on('focusin', function () { -      return $(this).select().one('mouseup', function (e) { -        return e.preventDefault(); -      }); -    // Click a .js-select-on-focus field, select the contents -    // Prevent a mouseup event from deselecting the input -    }); -    $('.remove-row').bind('ajax:success', function () { -      $(this).tooltip('destroy') -        .closest('li') -        .fadeOut(); -    }); -    $('.js-remove-tr').bind('ajax:before', function () { -      return $(this).hide(); -    }); -    $('.js-remove-tr').bind('ajax:success', function () { -      return $(this).closest('tr').fadeOut(); -    }); -    $('select.select2').select2({ -      width: 'resolve', -      // Initialize select2 selects -      dropdownAutoWidth: true -    }); -    $('.js-select2').bind('select2-close', function () { -      return setTimeout((function () { -        $('.select2-container-active').removeClass('select2-container-active'); -        return $(':focus').blur(); -      }), 1); -    // Close select2 on escape -    }); -    // Initialize tooltips -    $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; -    $body.tooltip({ -      selector: '.has-tooltip, [data-toggle="tooltip"]', -      placement: function (tip, el) { -        return $(el).data('placement') || 'bottom'; -      } -    }); -    $('.trigger-submit').on('change', function () { -      return $(this).parents('form').submit(); -    // Form submitter -    }); -    gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true); -    // Flash -    if ($flash.length > 0) { -      $flash.click(function () { -        return $(this).fadeOut(); -      }); -      $flash.show(); +  // prevent default action for disabled buttons +  $('.btn').click(function(e) { +    if ($(this).hasClass('disabled')) { +      e.preventDefault(); +      e.stopImmediatePropagation(); +      return false;      } -    // Disable form buttons while a form is submitting -    $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) { -      var buttons; -      buttons = $('[type="submit"]', this); -      switch (e.type) { -        case 'ajax:beforeSend': -        case 'submit': -          return buttons.disable(); -        default: -          return buttons.enable(); -      } -    }); -    $(document).ajaxError(function (e, xhrObj) { -      var ref = xhrObj.status; -      if (xhrObj.status === 401) { -        return new Flash('You need to be logged in.', 'alert'); -      } else if (ref === 404 || ref === 500) { -        return new Flash('Something went wrong on our end.', 'alert'); -      } -    }); -    $('.account-box').hover(function () { -      // Show/Hide the profile menu when hovering the account box -      return $(this).toggleClass('hover'); -    }); -    $document.on('click', '.diff-content .js-show-suppressed-diff', function () { -      var $container; -      $container = $(this).parent(); -      $container.next('table').show(); -      return $container.remove(); -    // Commit show suppressed diff -    }); -    $('.navbar-toggle').on('click', function () { -      $('.header-content .title').toggle(); -      $('.header-content .header-logo').toggle(); -      $('.header-content .navbar-collapse').toggle(); -      return $('.navbar-toggle').toggleClass('active'); -    }); -    // Show/hide comments on diff -    $body.on('click', '.js-toggle-diff-comments', function (e) { -      var $this = $(this); -      var notesHolders = $this.closest('.diff-file').find('.notes_holder'); -      $this.toggleClass('active'); -      if ($this.hasClass('active')) { -        notesHolders.show().find('.hide, .content').show(); -      } else { -        notesHolders.hide().find('.content').hide(); -      } -      $(document).trigger('toggle.comments'); +  }); + +  $('.js-select-on-focus').on('focusin', function () { +    return $(this).select().one('mouseup', function (e) {        return e.preventDefault();      }); -    $document.off('click', '.js-confirm-danger'); -    $document.on('click', '.js-confirm-danger', function (e) { -      var btn = $(e.target); -      var form = btn.closest('form'); -      var text = btn.data('confirm-danger-message'); -      e.preventDefault(); -      return new ConfirmDangerModal(form, text); -    }); -    $('input[type="search"]').each(function () { -      var $this = $(this); -      $this.attr('value', $this.val()); -    }); -    $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function () { -      var $this; -      $this = $(this); -      return $this.attr('value', $this.val()); -    }); -    $document.off('breakpoint:change').on('breakpoint:change', function (e, breakpoint) { -      var $gutterIcon; -      if (breakpoint === 'sm' || breakpoint === 'xs') { -        $gutterIcon = $sidebarGutterToggle.find('i'); -        if ($gutterIcon.hasClass('fa-angle-double-right')) { -          return $sidebarGutterToggle.trigger('click'); -        } -      } +  // Click a .js-select-on-focus field, select the contents +  // Prevent a mouseup event from deselecting the input +  }); +  $('.remove-row').bind('ajax:success', function () { +    $(this).tooltip('destroy') +      .closest('li') +      .fadeOut(); +  }); +  $('.js-remove-tr').bind('ajax:before', function () { +    return $(this).hide(); +  }); +  $('.js-remove-tr').bind('ajax:success', function () { +    return $(this).closest('tr').fadeOut(); +  }); +  $('select.select2').select2({ +    width: 'resolve', +    // Initialize select2 selects +    dropdownAutoWidth: true +  }); +  $('.js-select2').bind('select2-close', function () { +    return setTimeout((function () { +      $('.select2-container-active').removeClass('select2-container-active'); +      return $(':focus').blur(); +    }), 1); +  // Close select2 on escape +  }); +  // Initialize tooltips +  $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; +  $body.tooltip({ +    selector: '.has-tooltip, [data-toggle="tooltip"]', +    placement: function (tip, el) { +      return $(el).data('placement') || 'bottom'; +    } +  }); +  $('.trigger-submit').on('change', function () { +    return $(this).parents('form').submit(); +  // Form submitter +  }); +  gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true); +  // Flash +  if ($flash.length > 0) { +    $flash.click(function () { +      return $(this).fadeOut();      }); -    fitSidebarForSize = function () { -      var oldBootstrapBreakpoint; -      oldBootstrapBreakpoint = bootstrapBreakpoint; -      bootstrapBreakpoint = bp.getBreakpointSize(); -      if (bootstrapBreakpoint !== oldBootstrapBreakpoint) { -        return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); +    $flash.show(); +  } +  // Disable form buttons while a form is submitting +  $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) { +    var buttons; +    buttons = $('[type="submit"]', this); +    switch (e.type) { +      case 'ajax:beforeSend': +      case 'submit': +        return buttons.disable(); +      default: +        return buttons.enable(); +    } +  }); +  $(document).ajaxError(function (e, xhrObj) { +    var ref = xhrObj.status; +    if (xhrObj.status === 401) { +      return new Flash('You need to be logged in.', 'alert'); +    } else if (ref === 404 || ref === 500) { +      return new Flash('Something went wrong on our end.', 'alert'); +    } +  }); +  $('.account-box').hover(function () { +    // Show/Hide the profile menu when hovering the account box +    return $(this).toggleClass('hover'); +  }); +  $document.on('click', '.diff-content .js-show-suppressed-diff', function () { +    var $container; +    $container = $(this).parent(); +    $container.next('table').show(); +    return $container.remove(); +  // Commit show suppressed diff +  }); +  $('.navbar-toggle').on('click', function () { +    $('.header-content .title').toggle(); +    $('.header-content .header-logo').toggle(); +    $('.header-content .navbar-collapse').toggle(); +    return $('.navbar-toggle').toggleClass('active'); +  }); +  // Show/hide comments on diff +  $body.on('click', '.js-toggle-diff-comments', function (e) { +    var $this = $(this); +    var notesHolders = $this.closest('.diff-file').find('.notes_holder'); +    $this.toggleClass('active'); +    if ($this.hasClass('active')) { +      notesHolders.show().find('.hide, .content').show(); +    } else { +      notesHolders.hide().find('.content').hide(); +    } +    $(document).trigger('toggle.comments'); +    return e.preventDefault(); +  }); +  $document.off('click', '.js-confirm-danger'); +  $document.on('click', '.js-confirm-danger', function (e) { +    var btn = $(e.target); +    var form = btn.closest('form'); +    var text = btn.data('confirm-danger-message'); +    e.preventDefault(); +    return new ConfirmDangerModal(form, text); +  }); +  $('input[type="search"]').each(function () { +    var $this = $(this); +    $this.attr('value', $this.val()); +  }); +  $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function () { +    var $this; +    $this = $(this); +    return $this.attr('value', $this.val()); +  }); +  $document.off('breakpoint:change').on('breakpoint:change', function (e, breakpoint) { +    var $gutterIcon; +    if (breakpoint === 'sm' || breakpoint === 'xs') { +      $gutterIcon = $sidebarGutterToggle.find('i'); +      if ($gutterIcon.hasClass('fa-angle-double-right')) { +        return $sidebarGutterToggle.trigger('click');        } -    }; -    $window.off('resize.app').on('resize.app', function () { -      return fitSidebarForSize(); -    }); -    gl.awardsHandler = new AwardsHandler(); -    new Aside(); - -    gl.utils.initTimeagoTimeout(); +    }    }); -}).call(window); +  fitSidebarForSize = function () { +    var oldBootstrapBreakpoint; +    oldBootstrapBreakpoint = bootstrapBreakpoint; +    bootstrapBreakpoint = bp.getBreakpointSize(); +    if (bootstrapBreakpoint !== oldBootstrapBreakpoint) { +      return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); +    } +  }; +  $window.off('resize.app').on('resize.app', function () { +    return fitSidebarForSize(); +  }); +  gl.awardsHandler = new AwardsHandler(); +  new Aside(); + +  gl.utils.initTimeagoTimeout(); +}); | 
