Commit 28d412e5 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'prettify-all-the-things-8' into 'master'

Prettify all the things (part 8)

See merge request gitlab-org/gitlab-ce!22258
parents 10cc335c c559bcca
...@@ -26,14 +26,17 @@ export default class IssuableIndex { ...@@ -26,14 +26,17 @@ export default class IssuableIndex {
static resetIncomingEmailToken() { static resetIncomingEmailToken() {
const $resetToken = $('.incoming-email-token-reset'); const $resetToken = $('.incoming-email-token-reset');
$resetToken.on('click', (e) => { $resetToken.on('click', e => {
e.preventDefault(); e.preventDefault();
$resetToken.text('resetting...'); $resetToken.text('resetting...');
axios.put($resetToken.attr('href')) axios
.put($resetToken.attr('href'))
.then(({ data }) => { .then(({ data }) => {
$('#issuable_email').val(data.new_address).focus(); $('#issuable_email')
.val(data.new_address)
.focus();
$resetToken.text('reset it'); $resetToken.text('reset it');
}) })
......
...@@ -28,7 +28,7 @@ export default class Issue { ...@@ -28,7 +28,7 @@ export default class Issue {
} }
// Listen to state changes in the Vue app // Listen to state changes in the Vue app
document.addEventListener('issuable_vue_app:change', (event) => { document.addEventListener('issuable_vue_app:change', event => {
this.updateTopState(event.detail.isClosed, event.detail.data); this.updateTopState(event.detail.isClosed, event.detail.data);
}); });
} }
...@@ -55,7 +55,13 @@ export default class Issue { ...@@ -55,7 +55,13 @@ export default class Issue {
$(document).trigger('issuable:change', isClosed); $(document).trigger('issuable:change', isClosed);
this.toggleCloseReopenButton(isClosed); this.toggleCloseReopenButton(isClosed);
let numProjectIssues = Number(projectIssuesCounter.first().text().trim().replace(/[^\d]/, '')); let numProjectIssues = Number(
projectIssuesCounter
.first()
.text()
.trim()
.replace(/[^\d]/, ''),
);
numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1; numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
projectIssuesCounter.text(addDelimiter(numProjectIssues)); projectIssuesCounter.text(addDelimiter(numProjectIssues));
...@@ -76,29 +82,34 @@ export default class Issue { ...@@ -76,29 +82,34 @@ export default class Issue {
initIssueBtnEventListeners() { initIssueBtnEventListeners() {
const issueFailMessage = 'Unable to update this issue at this time.'; const issueFailMessage = 'Unable to update this issue at this time.';
return $(document).on('click', '.js-issuable-actions a.btn-close, .js-issuable-actions a.btn-reopen', (e) => { return $(document).on(
var $button, shouldSubmit, url; 'click',
e.preventDefault(); '.js-issuable-actions a.btn-close, .js-issuable-actions a.btn-reopen',
e.stopImmediatePropagation(); e => {
$button = $(e.currentTarget); var $button, shouldSubmit, url;
shouldSubmit = $button.hasClass('btn-comment'); e.preventDefault();
if (shouldSubmit) { e.stopImmediatePropagation();
Issue.submitNoteForm($button.closest('form')); $button = $(e.currentTarget);
} shouldSubmit = $button.hasClass('btn-comment');
if (shouldSubmit) {
this.disableCloseReopenButton($button); Issue.submitNoteForm($button.closest('form'));
}
url = $button.attr('href'); this.disableCloseReopenButton($button);
return axios.put(url)
.then(({ data }) => { url = $button.attr('href');
const isClosed = $button.hasClass('btn-close'); return axios
this.updateTopState(isClosed, data); .put(url)
}) .then(({ data }) => {
.catch(() => flash(issueFailMessage)) const isClosed = $button.hasClass('btn-close');
.then(() => { this.updateTopState(isClosed, data);
this.disableCloseReopenButton($button, false); })
}); .catch(() => flash(issueFailMessage))
}); .then(() => {
this.disableCloseReopenButton($button, false);
});
},
);
} }
initCloseReopenReport() { initCloseReopenReport() {
...@@ -124,7 +135,7 @@ export default class Issue { ...@@ -124,7 +135,7 @@ export default class Issue {
static submitNoteForm(form) { static submitNoteForm(form) {
var noteText; var noteText;
noteText = form.find("textarea.js-note-text").val(); noteText = form.find('textarea.js-note-text').val();
if (noteText && noteText.trim().length > 0) { if (noteText && noteText.trim().length > 0) {
return form.submit(); return form.submit();
} }
...@@ -133,22 +144,26 @@ export default class Issue { ...@@ -133,22 +144,26 @@ export default class Issue {
static initMergeRequests() { static initMergeRequests() {
var $container; var $container;
$container = $('#merge-requests'); $container = $('#merge-requests');
return axios.get($container.data('url')) return axios
.get($container.data('url'))
.then(({ data }) => { .then(({ data }) => {
if ('html' in data) { if ('html' in data) {
$container.html(data.html); $container.html(data.html);
} }
}).catch(() => flash('Failed to load referenced merge requests')); })
.catch(() => flash('Failed to load referenced merge requests'));
} }
static initRelatedBranches() { static initRelatedBranches() {
var $container; var $container;
$container = $('#related-branches'); $container = $('#related-branches');
return axios.get($container.data('url')) return axios
.get($container.data('url'))
.then(({ data }) => { .then(({ data }) => {
if ('html' in data) { if ('html' in data) {
$container.html(data.html); $container.html(data.html);
} }
}).catch(() => flash('Failed to load related branches')); })
.catch(() => flash('Failed to load related branches'));
} }
} }
...@@ -42,16 +42,14 @@ export default class Job extends LogOutputBehaviours { ...@@ -42,16 +42,14 @@ export default class Job extends LogOutputBehaviours {
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
this.$window this.$window.off('scroll').on('scroll', () => {
.off('scroll') if (!isScrolledToBottom()) {
.on('scroll', () => { this.toggleScrollAnimation(false);
if (!isScrolledToBottom()) { } else if (isScrolledToBottom() && !this.isLogComplete) {
this.toggleScrollAnimation(false); this.toggleScrollAnimation(true);
} else if (isScrolledToBottom() && !this.isLogComplete) { }
this.toggleScrollAnimation(true); this.scrollThrottled();
} });
this.scrollThrottled();
});
this.$window this.$window
.off('resize.build') .off('resize.build')
...@@ -87,10 +85,11 @@ export default class Job extends LogOutputBehaviours { ...@@ -87,10 +85,11 @@ export default class Job extends LogOutputBehaviours {
} }
getBuildTrace() { getBuildTrace() {
return axios.get(`${this.pagePath}/trace.json`, { return axios
params: { state: this.state }, .get(`${this.pagePath}/trace.json`, {
}) params: { state: this.state },
.then((res) => { })
.then(res => {
const log = res.data; const log = res.data;
if (!this.fetchingStatusFavicon) { if (!this.fetchingStatusFavicon) {
...@@ -186,5 +185,4 @@ export default class Job extends LogOutputBehaviours { ...@@ -186,5 +185,4 @@ export default class Job extends LogOutputBehaviours {
sidebarOnClick() { sidebarOnClick() {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
} }
} }
...@@ -47,7 +47,10 @@ export default class LabelManager { ...@@ -47,7 +47,10 @@ export default class LabelManager {
} }
toggleEmptyState($label, $btn, action) { toggleEmptyState($label, $btn, action) {
this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li')); this.emptyState.classList.toggle(
'hidden',
!!this.prioritizedLabels[0].querySelector(':scope > li'),
);
} }
toggleLabelPriority($label, action, persistState) { toggleLabelPriority($label, action, persistState) {
...@@ -80,16 +83,14 @@ export default class LabelManager { ...@@ -80,16 +83,14 @@ export default class LabelManager {
return; return;
} }
if (action === 'remove') { if (action === 'remove') {
axios.delete(url) axios.delete(url).catch(rollbackLabelPosition);
.catch(rollbackLabelPosition);
// Restore empty message // Restore empty message
if (!$from.find('li').length) { if (!$from.find('li').length) {
$from.find('.empty-message').removeClass('hidden'); $from.find('.empty-message').removeClass('hidden');
} }
} else { } else {
this.savePrioritySort($label, action) this.savePrioritySort($label, action).catch(rollbackLabelPosition);
.catch(rollbackLabelPosition);
} }
} }
...@@ -102,8 +103,7 @@ export default class LabelManager { ...@@ -102,8 +103,7 @@ export default class LabelManager {
} }
onPrioritySortUpdate() { onPrioritySortUpdate() {
this.savePrioritySort() this.savePrioritySort().catch(() => flash(this.errorMessage));
.catch(() => flash(this.errorMessage));
} }
savePrioritySort() { savePrioritySort() {
......
...@@ -22,7 +22,7 @@ export default class Labels { ...@@ -22,7 +22,7 @@ export default class Labels {
updateColorPreview() { updateColorPreview() {
const previewColor = $('input#label_color').val(); const previewColor = $('input#label_color').val();
return $('div.label-color-preview').css('background-color', previewColor); return $('div.label-color-preview').css('background-color', previewColor);
// Updates the the preview color with the hex-color input // Updates the the preview color with the hex-color input
} }
// Updates the preview color with a click on a suggested color // Updates the preview color with a click on a suggested color
......
...@@ -5,7 +5,9 @@ import initFlyOutNav from './fly_out_nav'; ...@@ -5,7 +5,9 @@ import initFlyOutNav from './fly_out_nav';
function hideEndFade($scrollingTabs) { function hideEndFade($scrollingTabs) {
$scrollingTabs.each(function scrollTabsLoop() { $scrollingTabs.each(function scrollTabsLoop() {
const $this = $(this); const $this = $(this);
$this.siblings('.fade-right').toggleClass('scrolling', Math.round($this.width()) < $this.prop('scrollWidth')); $this
.siblings('.fade-right')
.toggleClass('scrolling', Math.round($this.width()) < $this.prop('scrollWidth'));
}); });
} }
...@@ -15,38 +17,42 @@ export default function initLayoutNav() { ...@@ -15,38 +17,42 @@ export default function initLayoutNav() {
initFlyOutNav(); initFlyOutNav();
$(document).on('init.scrolling-tabs', () => { $(document)
const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized'); .on('init.scrolling-tabs', () => {
$scrollingTabs.addClass('is-initialized'); const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized');
$scrollingTabs.addClass('is-initialized');
$(window).on('resize.nav', () => { $(window)
hideEndFade($scrollingTabs); .on('resize.nav', () => {
}).trigger('resize.nav'); hideEndFade($scrollingTabs);
})
.trigger('resize.nav');
$scrollingTabs.on('scroll', function tabsScrollEvent() { $scrollingTabs.on('scroll', function tabsScrollEvent() {
const $this = $(this); const $this = $(this);
const currentPosition = $this.scrollLeft(); const currentPosition = $this.scrollLeft();
const maxPosition = $this.prop('scrollWidth') - $this.outerWidth(); const maxPosition = $this.prop('scrollWidth') - $this.outerWidth();
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0); $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
$this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1); $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
}); });
$scrollingTabs.each(function scrollTabsEachLoop() { $scrollingTabs.each(function scrollTabsEachLoop() {
const $this = $(this); const $this = $(this);
const scrollingTabWidth = $this.width(); const scrollingTabWidth = $this.width();
const $active = $this.find('.active'); const $active = $this.find('.active');
const activeWidth = $active.width(); const activeWidth = $active.width();
if ($active.length) { if ($active.length) {
const offset = $active.offset().left + activeWidth; const offset = $active.offset().left + activeWidth;
if (offset > scrollingTabWidth - 30) { if (offset > scrollingTabWidth - 30) {
const scrollLeft = (offset - (scrollingTabWidth / 2)) - (activeWidth / 2); const scrollLeft = offset - scrollingTabWidth / 2 - activeWidth / 2;
$this.scrollLeft(scrollLeft); $this.scrollLeft(scrollLeft);
}
} }
} });
}); })
}).trigger('init.scrolling-tabs'); .trigger('init.scrolling-tabs');
} }
...@@ -70,7 +70,7 @@ LineHighlighter.prototype.highlightHash = function(newHash) { ...@@ -70,7 +70,7 @@ LineHighlighter.prototype.highlightHash = function(newHash) {
const scrollOptions = { const scrollOptions = {
// Scroll to the first highlighted line on initial load // Scroll to the first highlighted line on initial load
// Offset -50 for the sticky top bar, and another -100 for some context // Offset -50 for the sticky top bar, and another -100 for some context
offset: -150 offset: -150,
}; };
if (this.options.scrollFileHolder) { if (this.options.scrollFileHolder) {
$(this.options.fileHolderSelector).scrollTo(lineSelector, scrollOptions); $(this.options.fileHolderSelector).scrollTo(lineSelector, scrollOptions);
...@@ -85,7 +85,9 @@ LineHighlighter.prototype.clickHandler = function(event) { ...@@ -85,7 +85,9 @@ LineHighlighter.prototype.clickHandler = function(event) {
var current, lineNumber, range; var current, lineNumber, range;
event.preventDefault(); event.preventDefault();
this.clearHighlight(); this.clearHighlight();
lineNumber = $(event.target).closest('a').data('lineNumber'); lineNumber = $(event.target)
.closest('a')
.data('lineNumber');
current = this.hashToRange(this._hash); current = this.hashToRange(this._hash);
if (!(current[0] && event.shiftKey)) { if (!(current[0] && event.shiftKey)) {
// If there's no current selection, or there is but Shift wasn't held, // If there's no current selection, or there is but Shift wasn't held,
...@@ -104,7 +106,7 @@ LineHighlighter.prototype.clickHandler = function(event) { ...@@ -104,7 +106,7 @@ LineHighlighter.prototype.clickHandler = function(event) {
}; };
LineHighlighter.prototype.clearHighlight = function() { LineHighlighter.prototype.clearHighlight = function() {
return $("." + this.highlightLineClass).removeClass(this.highlightLineClass); return $('.' + this.highlightLineClass).removeClass(this.highlightLineClass);
}; };
// Convert a URL hash String into line numbers // Convert a URL hash String into line numbers
...@@ -135,7 +137,7 @@ LineHighlighter.prototype.hashToRange = function(hash) { ...@@ -135,7 +137,7 @@ LineHighlighter.prototype.hashToRange = function(hash) {
// //
// lineNumber - Line number to highlight // lineNumber - Line number to highlight
LineHighlighter.prototype.highlightLine = function(lineNumber) { LineHighlighter.prototype.highlightLine = function(lineNumber) {
return $("#LC" + lineNumber).addClass(this.highlightLineClass); return $('#LC' + lineNumber).addClass(this.highlightLineClass);
}; };
// Highlight all lines within a range // Highlight all lines within a range
...@@ -160,9 +162,9 @@ LineHighlighter.prototype.highlightRange = function(range) { ...@@ -160,9 +162,9 @@ LineHighlighter.prototype.highlightRange = function(range) {
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) { LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
var hash; var hash;
if (lastLineNumber) { if (lastLineNumber) {
hash = "#L" + firstLineNumber + "-" + lastLineNumber; hash = '#L' + firstLineNumber + '-' + lastLineNumber;
} else { } else {
hash = "#L" + firstLineNumber; hash = '#L' + firstLineNumber;
} }
this._hash = hash; this._hash = hash;
return this.__setLocationHash__(hash); return this.__setLocationHash__(hash);
...@@ -172,11 +174,15 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) { ...@@ -172,11 +174,15 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
// //
// This method is stubbed in tests. // This method is stubbed in tests.
LineHighlighter.prototype.__setLocationHash__ = function(value) { LineHighlighter.prototype.__setLocationHash__ = function(value) {
return window.history.pushState({ return window.history.pushState(
url: value {
// We're using pushState instead of assigning location.hash directly to url: value,
// prevent the page from scrolling on the hashchange event // We're using pushState instead of assigning location.hash directly to
}, document.title, value); // prevent the page from scrolling on the hashchange event
},
document.title,
value,
);
}; };
export default LineHighlighter; export default LineHighlighter;
...@@ -15,7 +15,7 @@ export default (input, parameters, escapeParameters = true) => { ...@@ -15,7 +15,7 @@ export default (input, parameters, escapeParameters = true) => {
let output = input; let output = input;
if (parameters) { if (parameters) {
Object.keys(parameters).forEach((parameterName) => { Object.keys(parameters).forEach(parameterName => {
const parameterValue = parameters[parameterName]; const parameterValue = parameters[parameterName];
const escapedParameterValue = escapeParameters ? _.escape(parameterValue) : parameterValue; const escapedParameterValue = escapeParameters ? _.escape(parameterValue) : parameterValue;
output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue); output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue);
......
...@@ -9,7 +9,9 @@ import { parsePikadayDate, pikadayToString } from './lib/utils/datefix'; ...@@ -9,7 +9,9 @@ import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
// //
export default function memberExpirationDate(selector = '.js-access-expiration-date') { export default function memberExpirationDate(selector = '.js-access-expiration-date') {
function toggleClearInput() { function toggleClearInput() {
$(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); $(this)
.closest('.clearable-input')
.toggleClass('has-value', $(this).val() !== '');
} }
const inputs = $(selector); const inputs = $(selector);
...@@ -40,7 +42,9 @@ export default function memberExpirationDate(selector = '.js-access-expiration-d ...@@ -40,7 +42,9 @@ export default function memberExpirationDate(selector = '.js-access-expiration-d
inputs.next('.js-clear-input').on('click', function clicked(event) { inputs.next('.js-clear-input').on('click', function clicked(event) {
event.preventDefault(); event.preventDefault();
const input = $(this).closest('.clearable-input').find(selector); const input = $(this)
.closest('.clearable-input')
.find(selector);
const calendar = input.data('pikaday'); const calendar = input.data('pikaday');
calendar.setDate(null); calendar.setDate(null);
......
...@@ -16,26 +16,29 @@ function MergeRequest(opts) { ...@@ -16,26 +16,29 @@ function MergeRequest(opts) {
this.opts = opts != null ? opts : {}; this.opts = opts != null ? opts : {};
this.submitNoteForm = this.submitNoteForm.bind(this); this.submitNoteForm = this.submitNoteForm.bind(this);
this.$el = $('.merge-request'); this.$el = $('.merge-request');
this.$('.show-all-commits').on('click', (function(_this) { this.$('.show-all-commits').on(
return function() { 'click',
return _this.showAllCommits(); (function(_this) {
}; return function() {
})(this)); return _this.showAllCommits();
};
})(this),
);
this.initTabs(); this.initTabs();
this.initMRBtnListeners(); this.initMRBtnListeners();
this.initCommitMessageListeners(); this.initCommitMessageListeners();
this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport(); this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport();
if ($("a.btn-close").length) { if ($('a.btn-close').length) {
this.taskList = new TaskList({ this.taskList = new TaskList({
dataType: 'merge_request', dataType: 'merge_request',
fieldName: 'description', fieldName: 'description',
selector: '.detail-page-description', selector: '.detail-page-description',
onSuccess: (result) => { onSuccess: result => {
document.querySelector('#task_status').innerText = result.task_status; document.querySelector('#task_status').innerText = result.task_status;
document.querySelector('#task_status_short').innerText = result.task_status_short; document.querySelector('#task_status_short').innerText = result.task_status_short;
} },
}); });
} }
} }
...@@ -84,7 +87,7 @@ MergeRequest.prototype.initMRBtnListeners = function() { ...@@ -84,7 +87,7 @@ MergeRequest.prototype.initMRBtnListeners = function() {
MergeRequest.prototype.submitNoteForm = function(form, $button) { MergeRequest.prototype.submitNoteForm = function(form, $button) {
var noteText; var noteText;
noteText = form.find("textarea.js-note-text").val(); noteText = form.find('textarea.js-note-text').val();
if (noteText.trim().length > 0) { if (noteText.trim().length > 0) {
form.submit(); form.submit();
$button.data('submitted', true); $button.data('submitted', true);
...@@ -122,7 +125,7 @@ MergeRequest.setStatusBoxToMerged = function() { ...@@ -122,7 +125,7 @@ MergeRequest.setStatusBoxToMerged = function() {
MergeRequest.decreaseCounter = function(by = 1) { MergeRequest.decreaseCounter = function(by = 1) {
const $el = $('.js-merge-counter'); const $el = $('.js-merge-counter');
const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); const count = Math.max(parseInt($el.text().replace(/[^\d]/, ''), 10) - by, 0);
$el.text(addDelimiter(count)); $el.text(addDelimiter(count));
}; };
......
...@@ -15,7 +15,7 @@ export default class Milestone { ...@@ -15,7 +15,7 @@ export default class Milestone {
} }
bindTabsSwitching() { bindTabsSwitching() {
return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { return $('a[data-toggle="tab"]').on('show.bs.tab', e => {
const $target = $(e.target); const $target = $(e.target);
window.location.hash = $target.attr('href'); window.location.hash = $target.attr('href');
...@@ -36,7 +36,8 @@ export default class Milestone { ...@@ -36,7 +36,8 @@ export default class Milestone {
const tabElId = $target.attr('href'); const tabElId = $target.attr('href');
if (endpoint && !$target.hasClass('is-loaded')) { if (endpoint && !$target.hasClass('is-loaded')) {
axios.get(endpoint) axios
.get(endpoint)
.then(({ data }) => { .then(({ data }) => {
$(tabElId).html(data.html); $(tabElId).html(data.html);
$target.addClass('is-loaded'); $target.addClass('is-loaded');
...@@ -46,23 +47,28 @@ export default class Milestone { ...@@ -46,23 +47,28 @@ export default class Milestone {
} }
static initDeprecationMessage() { static initDeprecationMessage() {
const deprecationMesssageContainer = document.querySelector('.js-milestone-deprecation-message'); const deprecationMesssageContainer = document.querySelector(
'.js-milestone-deprecation-message',
);
if (!deprecationMesssageContainer) return; if (!deprecationMesssageContainer) return;
const deprecationMessage = deprecationMesssageContainer.querySelector('.js-milestone-deprecation-message-template').innerHTML; const deprecationMessage = deprecationMesssageContainer.querySelector(
'.js-milestone-deprecation-message-template',
).innerHTML;
const $popover = $('.js-popover-link', deprecationMesssageContainer); const $popover = $('.js-popover-link', deprecationMesssageContainer);
const hideOnScroll = togglePopover.bind($popover, false); const hideOnScroll = togglePopover.bind($popover, false);
$popover.popover({ $popover
content: deprecationMessage, .popover({
html: true, content: deprecationMessage,
placement: 'bottom', html: true,
}) placement: 'bottom',
.on('mouseenter', mouseenter) })
.on('mouseleave', debouncedMouseleave()) .on('mouseenter', mouseenter)
.on('show.bs.popover', () => { .on('mouseleave', debouncedMouseleave())
window.addEventListener('scroll', hideOnScroll, { once: true }); .on('show.bs.popover', () => {
}); window.addEventListener('scroll', hideOnScroll, { once: true });
});
} }
} }
...@@ -46,7 +46,7 @@ export default class MiniPipelineGraph { ...@@ -46,7 +46,7 @@ export default class MiniPipelineGraph {
$(document).on( $(document).on(
'click', 'click',
`${this.container} .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item`, `${this.container} .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item`,
(e) => { e => {
e.stopPropagation(); e.stopPropagation();
}, },
); );
...@@ -82,7 +82,8 @@ export default class MiniPipelineGraph { ...@@ -82,7 +82,8 @@ export default class MiniPipelineGraph {
this.renderBuildsList(button, ''); this.renderBuildsList(button, '');
this.toggleLoading(button); this.toggleLoading(button);
axios.get(endpoint) axios
.get(endpoint)
.then(({ data }) => { .then(({ data }) => {
this.toggleLoading(button); this.toggleLoading(button);
this.renderBuildsList(button, data.html); this.renderBuildsList(button, data.html);
...@@ -90,7 +91,11 @@ export default class MiniPipelineGraph { ...@@ -90,7 +91,11 @@ export default class MiniPipelineGraph {
}) })
.catch(() => { .catch(() => {
this.toggleLoading(button); this.toggleLoading(button);
if ($(button).parent().hasClass('open')) { if (
$(button)
.parent()
.hasClass('open')
) {
$(button).dropdown('toggle'); $(button).dropdown('toggle');
} }
flash('An error occurred while fetching the builds.', 'alert'); flash('An error occurred while fetching the builds.', 'alert');
...@@ -104,8 +109,8 @@ export default class MiniPipelineGraph { ...@@ -104,8 +109,8 @@ export default class MiniPipelineGraph {
* @return {type} * @return {type}
*/ */
toggleLoading(stageContainer) { toggleLoading(stageContainer) {
stageContainer.parentElement.querySelector( stageContainer.parentElement
`${this.dropdownListSelector} .js-builds-dropdown-loading`, .querySelector(`${this.dropdownListSelector} .js-builds-dropdown-loading`)
).classList.toggle('hidden'); .classList.toggle('hidden');
} }
} }
...@@ -14,14 +14,14 @@ export default class NamespaceSelect { ...@@ -14,14 +14,14 @@ export default class NamespaceSelect {
selectable: true, selectable: true,
filterRemote: true, filterRemote: true,
search: { search: {
fields: ['path'] fields: ['path'],
}, },
fieldName: fieldName, fieldName: fieldName,
toggleLabel: function(selected) { toggleLabel: function(selected) {
if (selected.id == null) { if (selected.id == null) {
return selected.text; return selected.text;
} else { } else {
return selected.kind + ": " + selected.full_path; return selected.kind + ': ' + selected.full_path;
} }
}, },
data: function(term, dataCallback) { data: function(term, dataCallback) {
...@@ -29,7 +29,7 @@ export default class NamespaceSelect { ...@@ -29,7 +29,7 @@ export default class NamespaceSelect {
if (isFilter) { if (isFilter) {
const anyNamespace = { const anyNamespace = {
text: 'Any namespace', text: 'Any namespace',
id: null id: null,
}; };
namespaces.unshift(anyNamespace); namespaces.unshift(anyNamespace);
namespaces.splice(1, 0, 'divider'); namespaces.splice(1, 0, 'divider');
...@@ -41,7 +41,7 @@ export default class NamespaceSelect { ...@@ -41,7 +41,7 @@ export default class NamespaceSelect {
if (namespace.id == null) { if (namespace.id == null) {
return namespace.text; return namespace.text;
} else { } else {
return namespace.kind + ": " + namespace.full_path; return namespace.kind + ': ' + namespace.full_path;
} }
}, },
renderRow: this.renderRow, renderRow: this.renderRow,
......
...@@ -20,7 +20,7 @@ export default (function() { ...@@ -20,7 +20,7 @@ export default (function() {
this.mtime = 0; this.mtime = 0;
this.mspace = 0; this.mspace = 0;
this.parents = {}; this.parents = {};
this.colors = ["#000"]; this.colors = ['#000'];
this.offsetX = 150; this.offsetX = 150;
this.offsetY = 20; this.offsetY = 20;
this.unitTime = 30; this.unitTime = 30;
...@@ -30,9 +30,10 @@ export default (function() { ...@@ -30,9 +30,10 @@ export default (function() {
} }
BranchGraph.prototype.load = function() { BranchGraph.prototype.load = function() {
axios.get(this.options.url) axios
.get(this.options.url)
.then(({ data }) => { .then(({ data }) => {
$(".loading", this.element).hide(); $('.loading', this.element).hide();
this.prepareData(data.days, data.commits); this.prepareData(data.days, data.commits);
this.buildGraph(); this.buildGraph();
}) })
...@@ -71,17 +72,19 @@ export default (function() { ...@@ -71,17 +72,19 @@ export default (function() {
c = ref[j]; c = ref[j];
this.mtime = Math.max(this.mtime, c.time); this.mtime = Math.max(this.mtime, c.time);
this.mspace = Math.max(this.mspace, c.space); this.mspace = Math.max(this.mspace, c.space);
results.push((function() { results.push(
var l, len1, ref1, results1; function() {
ref1 = c.parents; var l, len1, ref1, results1;
results1 = []; ref1 = c.parents;
for (l = 0, len1 = ref1.length; l < len1; l += 1) { results1 = [];
p = ref1[l]; for (l = 0, len1 = ref1.length; l < len1; l += 1) {
this.parents[p[0]] = true; p = ref1[l];
results1.push(this.mspace = Math.max(this.mspace, p[1])); this.parents[p[0]] = true;
} results1.push((this.mspace = Math.max(this.mspace, p[1])));
return results1; }
}).call(this)); return results1;
}.call(this),
);
} }
return results; return results;
}; };
...@@ -91,11 +94,11 @@ export default (function() { ...@@ -91,11 +94,11 @@ export default (function() {
k = 0; k = 0;
results = []; results = [];
while (k < this.mspace) { while (k < this.mspace) {
this.colors.push(Raphael.getColor(.8)); this.colors.push(Raphael.getColor(0.8));
// Skipping a few colors in the spectrum to get more contrast between colors // Skipping a few colors in the spectrum to get more contrast between colors
Raphael.getColor(); Raphael.getColor();
Raphael.getColor(); Raphael.getColor();
results.push(k += 1); results.push((k += 1));
} }
return results; return results;
}; };
...@@ -104,12 +107,12 @@ export default (function() { ...@@ -104,12 +107,12 @@ export default (function() {
var cuday, cumonth, day, j, len, mm, ref; var cuday, cumonth, day, j, len, mm, ref;
const { r } = this; const { r } = this;
cuday = 0; cuday = 0;
cumonth = ""; cumonth = '';
r.rect(0, 0, 40, this.barHeight).attr({ r.rect(0, 0, 40, this.barHeight).attr({
fill: "#222" fill: '#222',
}); });
r.rect(40, 0, 30, this.barHeight).attr({ r.rect(40, 0, 30, this.barHeight).attr({
fill: "#444" fill: '#444',
}); });
ref = this.days; ref = this.days;
...@@ -118,16 +121,16 @@ export default (function() { ...@@ -118,16 +121,16 @@ export default (function() {
if (cuday !== day[0] || cumonth !== day[1]) { if (cuday !== day[0] || cumonth !== day[1]) {
// Dates // Dates
r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({ r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({
font: "12px Monaco, monospace", font: '12px Monaco, monospace',
fill: "#BBB" fill: '#BBB',
}); });
[cuday] = day; [cuday] = day;
} }
if (cumonth !== day[1]) { if (cumonth !== day[1]) {
// Months // Months
r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({ r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({
font: "12px Monaco, monospace", font: '12px Monaco, monospace',
fill: "#EEE" fill: '#EEE',
}); });
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
...@@ -173,11 +176,13 @@ export default (function() { ...@@ -173,11 +176,13 @@ export default (function() {
BranchGraph.prototype.bindEvents = function() { BranchGraph.prototype.bindEvents = function() {
const { element } = this; const { element } = this;
return $(element).scroll((function(_this) { return $(element).scroll(
return function(event) { (function(_this) {
return _this.renderPartialGraph(); return function(event) {
}; return _this.renderPartialGraph();
})(this)); };
})(this),
);
}; };
BranchGraph.prototype.scrollDown = function() { BranchGraph.prototype.scrollDown = function() {
...@@ -219,46 +224,53 @@ export default (function() { ...@@ -219,46 +224,53 @@ export default (function() {
shortrefs = commit.refs; shortrefs = commit.refs;
// Truncate if longer than 15 chars // Truncate if longer than 15 chars
if (shortrefs.length > 17) { if (shortrefs.length > 17) {
shortrefs = shortrefs.substr(0, 15) + ""; shortrefs = shortrefs.substr(0, 15) + '';
} }
text = r.text(x + 4, y, shortrefs).attr({ text = r.text(x + 4, y, shortrefs).attr({
"text-anchor": "start", 'text-anchor': 'start',
font: "10px Monaco, monospace", font: '10px Monaco, monospace',
fill: "#FFF", fill: '#FFF',
title: commit.refs title: commit.refs,
}); });
textbox = text.getBBox(); textbox = text.getBBox();
// Create rectangle based on the size of the textbox // Create rectangle based on the size of the textbox
rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({ rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({
fill: "#000", fill: '#000',
"fill-opacity": .5, 'fill-opacity': 0.5,
stroke: "none" stroke: 'none',
}); });
triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({ triangle = r.path(['M', x - 5, y, 'L', x - 15, y - 4, 'L', x - 15, y + 4, 'Z']).attr({
fill: "#000", fill: '#000',
"fill-opacity": .5, 'fill-opacity': 0.5,
stroke: "none" stroke: 'none',
}); });
label = r.set(rect, text); label = r.set(rect, text);
label.transform(["t", -rect.getBBox().width - 15, 0]); label.transform(['t', -rect.getBBox().width - 15, 0]);
// Set text to front // Set text to front
return text.toFront(); return text.toFront();
}; };
BranchGraph.prototype.appendAnchor = function(x, y, commit) { BranchGraph.prototype.appendAnchor = function(x, y, commit) {
const { r, top, options } = this; const { r, top, options } = this;
const anchor = r.circle(x, y, 10).attr({ const anchor = r
fill: "#000", .circle(x, y, 10)
opacity: 0, .attr({
cursor: "pointer" fill: '#000',
}).click(function() { opacity: 0,
return window.open(options.commit_url.replace("%s", commit.id), "_blank"); cursor: 'pointer',
}).hover(function() { })
this.tooltip = r.commitTooltip(x + 5, y, commit); .click(function() {
return top.push(this.tooltip.insertBefore(this)); return window.open(options.commit_url.replace('%s', commit.id), '_blank');
}, function() { })
return this.tooltip && this.tooltip.remove() && delete this.tooltip; .hover(
}); function() {
this.tooltip = r.commitTooltip(x + 5, y, commit);
return top.push(this.tooltip.insertBefore(this));
},
function() {
return this.tooltip && this.tooltip.remove() && delete this.tooltip;
},
);
return top.push(anchor); return top.push(anchor);
}; };
...@@ -266,7 +278,7 @@ export default (function() { ...@@ -266,7 +278,7 @@ export default (function() {
const { r } = this; const { r } = this;
r.circle(x, y, 3).attr({ r.circle(x, y, 3).attr({
fill: this.colors[commit.space], fill: this.colors[commit.space],
stroke: "none" stroke: 'none',
}); });
const avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10; const avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10;
...@@ -274,13 +286,15 @@ export default (function() { ...@@ -274,13 +286,15 @@ export default (function() {
r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({ r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({
stroke: this.colors[commit.space], stroke: this.colors[commit.space],
"stroke-width": 2 'stroke-width': 2,
}); });
r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20); r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20);
return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({ return r
"text-anchor": "start", .text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split('\n')[0])
font: "14px Monaco, monospace" .attr({
}); 'text-anchor': 'start',
font: '14px Monaco, monospace',
});
}; };
BranchGraph.prototype.drawLines = function(x, y, commit) { BranchGraph.prototype.drawLines = function(x, y, commit) {
...@@ -304,30 +318,32 @@ export default (function() { ...@@ -304,30 +318,32 @@ export default (function() {
// Build line shape // Build line shape
if (parent[1] === commit.space) { if (parent[1] === commit.space) {
offset = [0, 5]; offset = [0, 5];
arrow = "l-2,5,4,0,-2,-5,0,5"; arrow = 'l-2,5,4,0,-2,-5,0,5';
} else if (parent[1] < commit.space) { } else if (parent[1] < commit.space) {
offset = [3, 3]; offset = [3, 3];
arrow = "l5,0,-2,4,-3,-4,4,2"; arrow = 'l5,0,-2,4,-3,-4,4,2';
} else { } else {
offset = [-3, 3]; offset = [-3, 3];
arrow = "l-5,0,2,4,3,-4,-4,2"; arrow = 'l-5,0,2,4,3,-4,-4,2';
} }
// Start point // Start point
route = ["M", x + offset[0], y + offset[1]]; route = ['M', x + offset[0], y + offset[1]];
// Add arrow if not first parent // Add arrow if not first parent
if (i > 0) { if (i > 0) {
route.push(arrow); route.push(arrow);
} }
// Circumvent if overlap // Circumvent if overlap
if (commit.space !== parentCommit.space || commit.space !== parent[1]) { if (commit.space !== parentCommit.space || commit.space !== parent[1]) {
route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5); route.push('L', parentX2, y + 10, 'L', parentX2, parentY - 5);
} }
// End point // End point
route.push("L", parentX1, parentY); route.push('L', parentX1, parentY);
results.push(r.path(route).attr({ results.push(
stroke: color, r.path(route).attr({
"stroke-width": 2 stroke: color,
})); 'stroke-width': 2,
}),
);
} }
return results; return results;
}; };
...@@ -337,10 +353,10 @@ export default (function() { ...@@ -337,10 +353,10 @@ export default (function() {
const { r } = this; const { r } = this;
const x = this.offsetX + this.unitSpace * (this.mspace - commit.space); const x = this.offsetX + this.unitSpace * (this.mspace - commit.space);
const y = this.offsetY + this.unitTime * commit.time; const y = this.offsetY + this.unitTime * commit.time;
r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({ r.path(['M', x + 5, y, 'L', x + 15, y + 4, 'L', x + 15, y - 4, 'Z']).attr({
fill: "#000", fill: '#000',
"fill-opacity": .5, 'fill-opacity': 0.5,
stroke: "none" stroke: 'none',
}); });
// Displayed in the center // Displayed in the center
return this.element.scrollTop(y - this.graphHeight / 2); return this.element.scrollTop(y - this.graphHeight / 2);
......
...@@ -49,7 +49,7 @@ Raphael.prototype.textWrap = function testWrap(t, width) { ...@@ -49,7 +49,7 @@ Raphael.prototype.textWrap = function testWrap(t, width) {
const s = []; const s = [];
for (let j = 0, len = words.length; j < len; j += 1) { for (let j = 0, len = words.length; j < len; j += 1) {
const word = words[j]; const word = words[j];
if (x + (word.length * letterWidth) > width) { if (x + word.length * letterWidth > width) {
s.push('\n'); s.push('\n');
x = 0; x = 0;
} }
......
...@@ -30,24 +30,24 @@ export default class NewBranchForm { ...@@ -30,24 +30,24 @@ export default class NewBranchForm {
startsWith = { startsWith = {
pattern: /^(\/|\.)/g, pattern: /^(\/|\.)/g,
prefix: "can't start with", prefix: "can't start with",
conjunction: "or" conjunction: 'or',
}; };
endsWith = { endsWith = {
pattern: /(\/|\.|\.lock)$/g, pattern: /(\/|\.|\.lock)$/g,
prefix: "can't end in", prefix: "can't end in",
conjunction: "or" conjunction: 'or',
}; };
invalid = { invalid = {
pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g,
prefix: "can't contain", prefix: "can't contain",
conjunction: ", " conjunction: ', ',
}; };
single = { single = {
pattern: /^@+$/g, pattern: /^@+$/g,
prefix: "can't be", prefix: "can't be",
conjunction: "or" conjunction: 'or',
}; };
return this.restrictions = [startsWith, invalid, endsWith, single]; return (this.restrictions = [startsWith, invalid, endsWith, single]);
} }
validate() { validate() {
...@@ -73,7 +73,7 @@ export default class NewBranchForm { ...@@ -73,7 +73,7 @@ export default class NewBranchForm {
return "'" + value + "'"; return "'" + value + "'";
} }
}); });
return restriction.prefix + " " + (formatted.join(restriction.conjunction)); return restriction.prefix + ' ' + formatted.join(restriction.conjunction);
}; };
validator = (function(_this) { validator = (function(_this) {
return function(errors, restriction) { return function(errors, restriction) {
...@@ -88,7 +88,7 @@ export default class NewBranchForm { ...@@ -88,7 +88,7 @@ export default class NewBranchForm {
})(this); })(this);
errors = this.restrictions.reduce(validator, []); errors = this.restrictions.reduce(validator, []);
if (errors.length > 0) { if (errors.length > 0) {
errorMessage = $("<span/>").text(errors.join(', ')); errorMessage = $('<span/>').text(errors.join(', '));
return this.branchNameError.append(errorMessage); return this.branchNameError.append(errorMessage);
} }
} }
......
...@@ -6,9 +6,7 @@ export default class NewCommitForm { ...@@ -6,9 +6,7 @@ export default class NewCommitForm {
this.branchName = form.find('.js-branch-name'); this.branchName = form.find('.js-branch-name');
this.originalBranch = form.find('.js-original-branch'); this.originalBranch = form.find('.js-original-branch');
this.createMergeRequest = form.find('.js-create-merge-request'); this.createMergeRequest = form.find('.js-create-merge-request');
this.createMergeRequestContainer = form.find( this.createMergeRequestContainer = form.find('.js-create-merge-request-container');
'.js-create-merge-request-container',
);
this.branchName.keyup(this.renderDestination); this.branchName.keyup(this.renderDestination);
this.renderDestination(); this.renderDestination();
} }
......
...@@ -18,7 +18,9 @@ export default function notificationsDropdown() { ...@@ -18,7 +18,9 @@ export default function notificationsDropdown() {
$(document).on('ajax:success', '.notification-form', (e, data) => { $(document).on('ajax:success', '.notification-form', (e, data) => {
if (data.saved) { if (data.saved) {
$(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html); $(e.currentTarget)
.closest('.js-notification-dropdown')
.replaceWith(data.html);
} else { } else {
Flash('Failed to save new settings', 'alert'); Flash('Failed to save new settings', 'alert');
} }
......
...@@ -22,7 +22,8 @@ export default class NotificationsForm { ...@@ -22,7 +22,8 @@ export default class NotificationsForm {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
showCheckboxLoadingSpinner($parent) { showCheckboxLoadingSpinner($parent) {
$parent.addClass('is-loading') $parent
.addClass('is-loading')
.find('.custom-notification-event-loading') .find('.custom-notification-event-loading')
.removeClass('fa-check') .removeClass('fa-check')
.addClass('fa-spin fa-spinner') .addClass('fa-spin fa-spinner')
...@@ -38,9 +39,12 @@ export default class NotificationsForm { ...@@ -38,9 +39,12 @@ export default class NotificationsForm {
.then(({ data }) => { .then(({ data }) => {
$checkbox.enable(); $checkbox.enable();
if (data.saved) { if (data.saved) {
$parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done'); $parent
.find('.custom-notification-event-loading')
.toggleClass('fa-spin fa-spinner fa-check is-done');
setTimeout(() => { setTimeout(() => {
$parent.removeClass('is-loading') $parent
.removeClass('is-loading')
.find('.custom-notification-event-loading') .find('.custom-notification-event-loading')
.toggleClass('fa-spin fa-spinner fa-check is-done'); .toggleClass('fa-spin fa-spinner fa-check is-done');
}, 2000); }, 2000);
......
...@@ -24,22 +24,25 @@ export default { ...@@ -24,22 +24,25 @@ export default {
getOld() { getOld() {
this.loading.show(); this.loading.show();
axios.get(this.url, { axios
params: { .get(this.url, {
limit: this.limit, params: {
offset: this.offset, limit: this.limit,
}, offset: this.offset,
}).then(({ data }) => { },
this.append(data.count, this.prepareData(data.html)); })
this.callback(); .then(({ data }) => {
this.append(data.count, this.prepareData(data.html));
this.callback();
// keep loading until we've filled the viewport height // keep loading until we've filled the viewport height
if (!this.disable && !this.isScrollable()) { if (!this.disable && !this.isScrollable()) {
this.getOld(); this.getOld();
} else { } else {
this.loading.hide(); this.loading.hide();
} }
}).catch(() => this.loading.hide()); })
.catch(() => this.loading.hide());
}, },
append(count, html) { append(count, html) {
......
<script> <script>
import pdfjsLib from 'vendor/pdf'; import pdfjsLib from 'vendor/pdf';
import workerSrc from 'vendor/pdf.worker.min'; import workerSrc from 'vendor/pdf.worker.min';
import page from './page/index.vue'; import page from './page/index.vue';
export default { export default {
components: { page }, components: { page },
props: { props: {
pdf: { pdf: {
type: [String, Uint8Array], type: [String, Uint8Array],
required: true, required: true,
},
}, },
data() { },
return { data() {
loading: false, return {
pages: [], loading: false,
}; pages: [],
};
},
computed: {
document() {
return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf };
}, },
computed: { hasPDF() {
document() { return this.pdf && this.pdf.length > 0;
return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf };
},
hasPDF() {
return this.pdf && this.pdf.length > 0;
},
}, },
watch: { pdf: 'load' }, },
mounted() { watch: { pdf: 'load' },
pdfjsLib.PDFJS.workerSrc = workerSrc; mounted() {
if (this.hasPDF) this.load(); pdfjsLib.PDFJS.workerSrc = workerSrc;
if (this.hasPDF) this.load();
},
methods: {
load() {
this.pages = [];
return pdfjsLib
.getDocument(this.document)
.then(this.renderPages)
.then(() => this.$emit('pdflabload'))
.catch(error => this.$emit('pdflaberror', error))
.then(() => {
this.loading = false;
});
}, },
methods: { renderPages(pdf) {
load() { const pagePromises = [];
this.pages = []; this.loading = true;
return pdfjsLib.getDocument(this.document) for (let num = 1; num <= pdf.numPages; num += 1) {
.then(this.renderPages) pagePromises.push(pdf.getPage(num).then(p => this.pages.push(p)));
.then(() => this.$emit('pdflabload')) }
.catch(error => this.$emit('pdflaberror', error)) return Promise.all(pagePromises);
.then(() => { this.loading = false; });
},
renderPages(pdf) {
const pagePromises = [];
this.loading = true;
for (let num = 1; num <= pdf.numPages; num += 1) {
pagePromises.push(
pdf.getPage(num).then(p => this.pages.push(p)),
);
}
return Promise.all(pagePromises);
},
}, },
}; },
};
</script> </script>
<template> <template>
...@@ -69,9 +70,9 @@ ...@@ -69,9 +70,9 @@
</template> </template>
<style> <style>
.pdf-viewer { .pdf-viewer {
background: url('./assets/img/bg.gif'); background: url('./assets/img/bg.gif');
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
} }
</style> </style>
<script> <script>
export default { export default {
props: { props: {
page: { page: {
type: Object, type: Object,
required: true, required: true,
},
number: {
type: Number,
required: true,
},
}, },
data() { number: {
return { type: Number,
scale: 4, required: true,
rendering: false, },
}; },
data() {
return {
scale: 4,
rendering: false,
};
},
computed: {
viewport() {
return this.page.getViewport(this.scale);
}, },
computed: { context() {
viewport() { return this.$refs.canvas.getContext('2d');
return this.page.getViewport(this.scale);
},
context() {
return this.$refs.canvas.getContext('2d');
},
renderContext() {
return {
canvasContext: this.context,
viewport: this.viewport,
};
},
}, },
mounted() { renderContext() {
this.$refs.canvas.height = this.viewport.height; return {
this.$refs.canvas.width = this.viewport.width; canvasContext: this.context,
this.rendering = true; viewport: this.viewport,
this.page.render(this.renderContext) };
.then(() => { this.rendering = false; })
.catch(error => this.$emit('pdflaberror', error));
}, },
}; },
mounted() {
this.$refs.canvas.height = this.viewport.height;
this.$refs.canvas.width = this.viewport.width;
this.rendering = true;
this.page
.render(this.renderContext)
.then(() => {
this.rendering = false;
})
.catch(error => this.$emit('pdflaberror', error));
},
};
</script> </script>
<template> <template>
...@@ -51,20 +54,20 @@ ...@@ -51,20 +54,20 @@
</template> </template>
<style> <style>
.pdf-page { .pdf-page {
margin: 8px auto 0 auto; margin: 8px auto 0 auto;
border-top: 1px #ddd solid; border-top: 1px #ddd solid;
border-bottom: 1px #ddd solid; border-bottom: 1px #ddd solid;
width: 100%; width: 100%;
} }
.pdf-page:first-child { .pdf-page:first-child {
margin-top: 0px; margin-top: 0px;
border-top: 0px; border-top: 0px;
} }
.pdf-page:last-child { .pdf-page:last-child {
margin-bottom: 0px; margin-bottom: 0px;
border-bottom: 0px; border-bottom: 0px;
} }
</style> </style>
...@@ -64,10 +64,7 @@ export default { ...@@ -64,10 +64,7 @@ export default {
return []; return [];
} }
const { details } = this.pipeline; const { details } = this.pipeline;
return [ return [...(details.manual_actions || []), ...(details.scheduled_actions || [])];
...(details.manual_actions || []),
...(details.scheduled_actions || []),
];
}, },
/** /**
* If provided, returns the commit tag. * If provided, returns the commit tag.
......
...@@ -10,14 +10,14 @@ import { __ } from '~/locale'; ...@@ -10,14 +10,14 @@ import { __ } from '~/locale';
const highlighter = function(element, text, matches) { const highlighter = function(element, text, matches) {
var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched; var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched;
lastIndex = 0; lastIndex = 0;
highlightText = ""; highlightText = '';
matchedChars = []; matchedChars = [];
for (j = 0, len = matches.length; j < len; j += 1) { for (j = 0, len = matches.length; j < len; j += 1) {
matchIndex = matches[j]; matchIndex = matches[j];
unmatched = text.substring(lastIndex, matchIndex); unmatched = text.substring(lastIndex, matchIndex);
if (unmatched) { if (unmatched) {
if (matchedChars.length) { if (matchedChars.length) {
element.append(matchedChars.join("").bold()); element.append(matchedChars.join('').bold());
} }
matchedChars = []; matchedChars = [];
element.append(document.createTextNode(unmatched)); element.append(document.createTextNode(unmatched));
...@@ -26,7 +26,7 @@ const highlighter = function(element, text, matches) { ...@@ -26,7 +26,7 @@ const highlighter = function(element, text, matches) {
lastIndex = matchIndex + 1; lastIndex = matchIndex + 1;
} }
if (matchedChars.length) { if (matchedChars.length) {
element.append(matchedChars.join("").bold()); element.append(matchedChars.join('').bold());
} }
return element.append(document.createTextNode(text.substring(lastIndex))); return element.append(document.createTextNode(text.substring(lastIndex)));
}; };
...@@ -40,7 +40,7 @@ export default class ProjectFindFile { ...@@ -40,7 +40,7 @@ export default class ProjectFindFile {
this.selectRowDown = this.selectRowDown.bind(this); this.selectRowDown = this.selectRowDown.bind(this);
this.selectRowUp = this.selectRowUp.bind(this); this.selectRowUp = this.selectRowUp.bind(this);
this.filePaths = {}; this.filePaths = {};
this.inputElement = this.element.find(".file-finder-input"); this.inputElement = this.element.find('.file-finder-input');
// init event // init event
this.initEvent(); this.initEvent();
// focus text input box // focus text input box
...@@ -50,38 +50,51 @@ export default class ProjectFindFile { ...@@ -50,38 +50,51 @@ export default class ProjectFindFile {
} }
initEvent() { initEvent() {
this.inputElement.off("keyup"); this.inputElement.off('keyup');
this.inputElement.on("keyup", (function(_this) { this.inputElement.on(
return function(event) { 'keyup',
var oldValue, ref, target, value; (function(_this) {
target = $(event.target); return function(event) {
value = target.val(); var oldValue, ref, target, value;
oldValue = (ref = target.data("oldValue")) != null ? ref : ""; target = $(event.target);
if (value !== oldValue) { value = target.val();
target.data("oldValue", value); oldValue = (ref = target.data('oldValue')) != null ? ref : '';
_this.findFile(); if (value !== oldValue) {
return _this.element.find("tr.tree-item").eq(0).addClass("selected").focus(); target.data('oldValue', value);
} _this.findFile();
}; return _this.element
})(this)); .find('tr.tree-item')
.eq(0)
.addClass('selected')
.focus();
}
};
})(this),
);
} }
findFile() { findFile() {
var result, searchText; var result, searchText;
searchText = this.inputElement.val(); searchText = this.inputElement.val();
result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths; result =
searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
return this.renderList(result, searchText); return this.renderList(result, searchText);
// find file // find file
} }
// files pathes load // files pathes load
load(url) { load(url) {
axios.get(url) axios
.get(url)
.then(({ data }) => { .then(({ data }) => {
this.element.find('.loading').hide(); this.element.find('.loading').hide();
this.filePaths = data; this.filePaths = data;
this.findFile(); this.findFile();
this.element.find('.files-slider tr.tree-item').eq(0).addClass('selected').focus(); this.element
.find('.files-slider tr.tree-item')
.eq(0)
.addClass('selected')
.focus();
}) })
.catch(() => flash(__('An error occurred while loading filenames'))); .catch(() => flash(__('An error occurred while loading filenames')));
} }
...@@ -89,7 +102,7 @@ export default class ProjectFindFile { ...@@ -89,7 +102,7 @@ export default class ProjectFindFile {
// render result // render result
renderList(filePaths, searchText) { renderList(filePaths, searchText) {
var blobItemUrl, filePath, html, i, len, matches, results; var blobItemUrl, filePath, html, i, len, matches, results;
this.element.find(".tree-table > tbody").empty(); this.element.find('.tree-table > tbody').empty();
results = []; results = [];
for (i = 0, len = filePaths.length; i < len; i += 1) { for (i = 0, len = filePaths.length; i < len; i += 1) {
...@@ -100,9 +113,9 @@ export default class ProjectFindFile { ...@@ -100,9 +113,9 @@ export default class ProjectFindFile {
if (searchText) { if (searchText) {
matches = fuzzaldrinPlus.match(filePath, searchText); matches = fuzzaldrinPlus.match(filePath, searchText);
} }
blobItemUrl = this.options.blobUrlTemplate + "/" + filePath; blobItemUrl = this.options.blobUrlTemplate + '/' + filePath;
html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl); html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
results.push(this.element.find(".tree-table > tbody").append(html)); results.push(this.element.find('.tree-table > tbody').append(html));
} }
return results; return results;
} }
...@@ -110,52 +123,56 @@ export default class ProjectFindFile { ...@@ -110,52 +123,56 @@ export default class ProjectFindFile {
// make tbody row html // make tbody row html
static makeHtml(filePath, matches, blobItemUrl) { static makeHtml(filePath, matches, blobItemUrl) {
var $tr; var $tr;
$tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>"); $tr = $(
"<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>",
);
if (matches) { if (matches) {
$tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)); $tr
.find('a')
.replaceWith(highlighter($tr.find('a'), filePath, matches).attr('href', blobItemUrl));
} else { } else {
$tr.find("a").attr("href", blobItemUrl); $tr.find('a').attr('href', blobItemUrl);
$tr.find(".str-truncated").text(filePath); $tr.find('.str-truncated').text(filePath);
} }
return $tr; return $tr;
} }
selectRow(type) { selectRow(type) {
var next, rows, selectedRow; var next, rows, selectedRow;
rows = this.element.find(".files-slider tr.tree-item"); rows = this.element.find('.files-slider tr.tree-item');
selectedRow = this.element.find(".files-slider tr.tree-item.selected"); selectedRow = this.element.find('.files-slider tr.tree-item.selected');
if (rows && rows.length > 0) { if (rows && rows.length > 0) {
if (selectedRow && selectedRow.length > 0) { if (selectedRow && selectedRow.length > 0) {
if (type === "UP") { if (type === 'UP') {
next = selectedRow.prev(); next = selectedRow.prev();
} else if (type === "DOWN") { } else if (type === 'DOWN') {
next = selectedRow.next(); next = selectedRow.next();
} }
if (next.length > 0) { if (next.length > 0) {
selectedRow.removeClass("selected"); selectedRow.removeClass('selected');
selectedRow = next; selectedRow = next;
} }
} else { } else {
selectedRow = rows.eq(0); selectedRow = rows.eq(0);
} }
return selectedRow.addClass("selected").focus(); return selectedRow.addClass('selected').focus();
} }
} }
selectRowUp() { selectRowUp() {
return this.selectRow("UP"); return this.selectRow('UP');
} }
selectRowDown() { selectRowDown() {
return this.selectRow("DOWN"); return this.selectRow('DOWN');
} }
goToTree() { goToTree() {
return window.location.href = this.options.treeUrl; return (window.location.href = this.options.treeUrl);
} }
goToBlob() { goToBlob() {
var $link = this.element.find(".tree-item.selected .tree-item-file-name a"); var $link = this.element.find('.tree-item.selected .tree-item-file-name a');
if ($link.length) { if ($link.length) {
$link.get(0).click(); $link.get(0).click();
......
...@@ -5,4 +5,3 @@ export default function projectImport() { ...@@ -5,4 +5,3 @@ export default function projectImport() {
visitUrl(window.location.href); visitUrl(window.location.href);
}, 5000); }, 5000);
} }
...@@ -31,32 +31,35 @@ export default class ProjectLabelSubscription { ...@@ -31,32 +31,35 @@ export default class ProjectLabelSubscription {
$btn.addClass('disabled'); $btn.addClass('disabled');
axios.post(url).then(() => { axios
let newStatus; .post(url)
let newAction; .then(() => {
let newStatus;
let newAction;
if (oldStatus === 'unsubscribed') { if (oldStatus === 'unsubscribed') {
[newStatus, newAction] = ['subscribed', 'Unsubscribe']; [newStatus, newAction] = ['subscribed', 'Unsubscribe'];
} else { } else {
[newStatus, newAction] = ['unsubscribed', 'Subscribe']; [newStatus, newAction] = ['unsubscribed', 'Subscribe'];
} }
$btn.removeClass('disabled'); $btn.removeClass('disabled');
this.$buttons.attr('data-status', newStatus); this.$buttons.attr('data-status', newStatus);
this.$buttons.find('> span').text(newAction); this.$buttons.find('> span').text(newAction);
this.$buttons.map((i, button) => { this.$buttons.map((i, button) => {
const $button = $(button); const $button = $(button);
const originalTitle = $button.attr('data-original-title'); const originalTitle = $button.attr('data-original-title');
if (originalTitle) { if (originalTitle) {
ProjectLabelSubscription.setNewTitle($button, originalTitle, newStatus, newAction); ProjectLabelSubscription.setNewTitle($button, originalTitle, newStatus, newAction);
} }
return button; return button;
}); });
}).catch(() => flash(__('There was an error subscribing to this label.'))); })
.catch(() => flash(__('There was an error subscribing to this label.')));
} }
static setNewTitle($button, originalTitle, newStatus) { static setNewTitle($button, originalTitle, newStatus) {
......
...@@ -16,28 +16,28 @@ export default function projectSelect() { ...@@ -16,28 +16,28 @@ export default function projectSelect() {
this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
this.allowClear = $(select).data('allowClear') || false; this.allowClear = $(select).data('allowClear') || false;
placeholder = "Search for project"; placeholder = 'Search for project';
if (this.includeGroups) { if (this.includeGroups) {
placeholder += " or group"; placeholder += ' or group';
} }
$(select).select2({ $(select).select2({
placeholder: placeholder, placeholder: placeholder,
minimumInputLength: 0, minimumInputLength: 0,
query: (function (_this) { query: (function(_this) {
return function (query) { return function(query) {
var finalCallback, projectsCallback; var finalCallback, projectsCallback;
finalCallback = function (projects) { finalCallback = function(projects) {
var data; var data;
data = { data = {
results: projects results: projects,
}; };
return query.callback(data); return query.callback(data);
}; };
if (_this.includeGroups) { if (_this.includeGroups) {
projectsCallback = function (projects) { projectsCallback = function(projects) {
var groupsCallback; var groupsCallback;
groupsCallback = function (groups) { groupsCallback = function(groups) {
var data; var data;
data = groups.concat(projects); data = groups.concat(projects);
return finalCallback(data); return finalCallback(data);
...@@ -48,17 +48,26 @@ export default function projectSelect() { ...@@ -48,17 +48,26 @@ export default function projectSelect() {
projectsCallback = finalCallback; projectsCallback = finalCallback;
} }
if (_this.groupId) { if (_this.groupId) {
return Api.groupProjects(_this.groupId, query.term, { return Api.groupProjects(
with_issues_enabled: _this.withIssuesEnabled, _this.groupId,
with_merge_requests_enabled: _this.withMergeRequestsEnabled, query.term,
}, projectsCallback); {
with_issues_enabled: _this.withIssuesEnabled,
with_merge_requests_enabled: _this.withMergeRequestsEnabled,
},
projectsCallback,
);
} else { } else {
return Api.projects(query.term, { return Api.projects(
order_by: _this.orderBy, query.term,
with_issues_enabled: _this.withIssuesEnabled, {
with_merge_requests_enabled: _this.withMergeRequestsEnabled, order_by: _this.orderBy,
membership: !_this.allProjects, with_issues_enabled: _this.withIssuesEnabled,
}, projectsCallback); with_merge_requests_enabled: _this.withMergeRequestsEnabled,
membership: !_this.allProjects,
},
projectsCallback,
);
} }
}; };
})(this), })(this),
...@@ -69,7 +78,7 @@ export default function projectSelect() { ...@@ -69,7 +78,7 @@ export default function projectSelect() {
url: project.web_url, url: project.web_url,
}); });
}, },
text: function (project) { text: function(project) {
return project.name_with_namespace || project.name; return project.name_with_namespace || project.name;
}, },
...@@ -79,7 +88,7 @@ export default function projectSelect() { ...@@ -79,7 +88,7 @@ export default function projectSelect() {
allowClear: this.allowClear, allowClear: this.allowClear,
dropdownCssClass: "ajax-project-dropdown" dropdownCssClass: 'ajax-project-dropdown',
}); });
if (simpleFilter) return select; if (simpleFilter) return select;
return new ProjectSelectComboButton(select); return new ProjectSelectComboButton(select);
......
...@@ -14,10 +14,11 @@ export default class ProjectSelectComboButton { ...@@ -14,10 +14,11 @@ export default class ProjectSelectComboButton {
} }
bindEvents() { bindEvents() {
this.projectSelectInput.siblings('.new-project-item-select-button') this.projectSelectInput
.siblings('.new-project-item-select-button')
.on('click', e => this.openDropdown(e)); .on('click', e => this.openDropdown(e));
this.newItemBtn.on('click', (e) => { this.newItemBtn.on('click', e => {
if (!this.getProjectFromLocalStorage()) { if (!this.getProjectFromLocalStorage()) {
e.preventDefault(); e.preventDefault();
this.openDropdown(e); this.openDropdown(e);
...@@ -31,14 +32,21 @@ export default class ProjectSelectComboButton { ...@@ -31,14 +32,21 @@ export default class ProjectSelectComboButton {
const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe(); const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe();
if (localStorageIsSafe) { if (localStorageIsSafe) {
this.localStorageKey = ['group', this.groupId, this.formattedText.localStorageItemType, 'recent-project'].join('-'); this.localStorageKey = [
'group',
this.groupId,
this.formattedText.localStorageItemType,
'recent-project',
].join('-');
this.setBtnTextFromLocalStorage(); this.setBtnTextFromLocalStorage();
} }
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
openDropdown(event) { openDropdown(event) {
$(event.currentTarget).siblings('.project-item-select').select2('open'); $(event.currentTarget)
.siblings('.project-item-select')
.select2('open');
} }
selectProject() { selectProject() {
...@@ -86,8 +94,14 @@ export default class ProjectSelectComboButton { ...@@ -86,8 +94,14 @@ export default class ProjectSelectComboButton {
const defaultTextPrefix = this.resourceLabel; const defaultTextPrefix = this.resourceLabel;
// the trailing slice call depluralizes each of these strings (e.g. new-issues -> new-issue) // the trailing slice call depluralizes each of these strings (e.g. new-issues -> new-issue)
const localStorageItemType = `new-${this.resourceType.split('_').join('-').slice(0, -1)}`; const localStorageItemType = `new-${this.resourceType
const presetTextSuffix = this.resourceType.split('_').join(' ').slice(0, -1); .split('_')
.join('-')
.slice(0, -1)}`;
const presetTextSuffix = this.resourceType
.split('_')
.join(' ')
.slice(0, -1);
return { return {
localStorageItemType, // new-issue / new-merge-request localStorageItemType, // new-issue / new-merge-request
...@@ -96,4 +110,3 @@ export default class ProjectSelectComboButton { ...@@ -96,4 +110,3 @@ export default class ProjectSelectComboButton {
}; };
} }
} }
...@@ -7,7 +7,7 @@ function setVisibilityOptions(namespaceSelector) { ...@@ -7,7 +7,7 @@ function setVisibilityOptions(namespaceSelector) {
const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex]; const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex];
const { name, visibility, visibilityLevel, showPath, editPath } = selectedNamespace.dataset; const { name, visibility, visibilityLevel, showPath, editPath } = selectedNamespace.dataset;
document.querySelectorAll('.visibility-level-setting .form-check').forEach((option) => { document.querySelectorAll('.visibility-level-setting .form-check').forEach(option => {
const optionInput = option.querySelector('input[type=radio]'); const optionInput = option.querySelector('input[type=radio]');
const optionValue = optionInput ? optionInput.value : 0; const optionValue = optionInput ? optionInput.value : 0;
const optionTitle = option.querySelector('.option-title'); const optionTitle = option.querySelector('.option-title');
...@@ -20,8 +20,7 @@ function setVisibilityOptions(namespaceSelector) { ...@@ -20,8 +20,7 @@ function setVisibilityOptions(namespaceSelector) {
optionInput.disabled = true; optionInput.disabled = true;
const reason = option.querySelector('.option-disabled-reason'); const reason = option.querySelector('.option-disabled-reason');
if (reason) { if (reason) {
reason.innerHTML = reason.innerHTML = `This project cannot be ${optionName} because the visibility of
`This project cannot be ${optionName} because the visibility of
<a href="${showPath}">${name}</a> is ${visibility}. To make this project <a href="${showPath}">${name}</a> is ${visibility}. To make this project
${optionName}, you must first <a href="${editPath}">change the visibility</a> ${optionName}, you must first <a href="${editPath}">change the visibility</a>
of the parent group.`; of the parent group.`;
......
...@@ -65,10 +65,14 @@ export default class PrometheusMetrics { ...@@ -65,10 +65,14 @@ export default class PrometheusMetrics {
let totalMissingEnvVarMetrics = 0; let totalMissingEnvVarMetrics = 0;
let totalExporters = 0; let totalExporters = 0;
metrics.forEach((metric) => { metrics.forEach(metric => {
if (metric.active_metrics > 0) { if (metric.active_metrics > 0) {
totalExporters += 1; totalExporters += 1;
this.$monitoredMetricsList.append(`<li>${_.escape(metric.group)}<span class="badge">${_.escape(metric.active_metrics)}</span></li>`); this.$monitoredMetricsList.append(
`<li>${_.escape(metric.group)}<span class="badge">${_.escape(
metric.active_metrics,
)}</span></li>`,
);
totalMonitoredMetrics += metric.active_metrics; totalMonitoredMetrics += metric.active_metrics;
if (metric.metrics_missing_requirements > 0) { if (metric.metrics_missing_requirements > 0) {
this.$missingEnvVarMetricsList.append(`<li>${_.escape(metric.group)}</li>`); this.$missingEnvVarMetricsList.append(`<li>${_.escape(metric.group)}</li>`);
...@@ -78,17 +82,26 @@ export default class PrometheusMetrics { ...@@ -78,17 +82,26 @@ export default class PrometheusMetrics {
}); });
if (totalMonitoredMetrics === 0) { if (totalMonitoredMetrics === 0) {
const emptyCommonMetricsText = sprintf(s__('PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>'), { const emptyCommonMetricsText = sprintf(
docsUrl: this.helpMetricsPath, s__(
}, false); 'PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>',
),
{
docsUrl: this.helpMetricsPath,
},
false,
);
this.$monitoredMetricsEmpty.empty(); this.$monitoredMetricsEmpty.empty();
this.$monitoredMetricsEmpty.append(emptyCommonMetricsText); this.$monitoredMetricsEmpty.append(emptyCommonMetricsText);
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY); this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
} else { } else {
const metricsCountText = sprintf(s__('PrometheusService|%{exporters} with %{metrics} were found'), { const metricsCountText = sprintf(
exporters: n__('%d exporter', '%d exporters', totalExporters), s__('PrometheusService|%{exporters} with %{metrics} were found'),
metrics: n__('%d metric', '%d metrics', totalMonitoredMetrics), {
}); exporters: n__('%d exporter', '%d exporters', totalExporters),
metrics: n__('%d metric', '%d metrics', totalMonitoredMetrics),
},
);
this.$monitoredMetricsCount.text(metricsCountText); this.$monitoredMetricsCount.text(metricsCountText);
this.showMonitoringMetricsPanelState(PANEL_STATE.LIST); this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
...@@ -102,7 +115,8 @@ export default class PrometheusMetrics { ...@@ -102,7 +115,8 @@ export default class PrometheusMetrics {
loadActiveMetrics() { loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING); this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
backOff((next, stop) => { backOff((next, stop) => {
axios.get(this.activeMetricsEndpoint) axios
.get(this.activeMetricsEndpoint)
.then(({ data }) => { .then(({ data }) => {
if (data && data.success) { if (data && data.success) {
stop(data); stop(data);
...@@ -117,7 +131,7 @@ export default class PrometheusMetrics { ...@@ -117,7 +131,7 @@ export default class PrometheusMetrics {
}) })
.catch(stop); .catch(stop);
}) })
.then((res) => { .then(res => {
if (res && res.data && res.data.length) { if (res && res.data && res.data.length) {
this.populateActiveMetrics(res.data); this.populateActiveMetrics(res.data);
} else { } else {
......
...@@ -9,7 +9,7 @@ const IGNORE_ERRORS = [ ...@@ -9,7 +9,7 @@ const IGNORE_ERRORS = [
'canvas.contentDocument', 'canvas.contentDocument',
'MyApp_RemoveAllHighlights', 'MyApp_RemoveAllHighlights',
'http://tt.epicplay.com', 'http://tt.epicplay.com',
'Can\'t find variable: ZiteReader', "Can't find variable: ZiteReader",
'jigsaw is not defined', 'jigsaw is not defined',
'ComboSearch is not defined', 'ComboSearch is not defined',
'http://loading.retry.widdit.com/', 'http://loading.retry.widdit.com/',
......
...@@ -2,7 +2,8 @@ import $ from 'jquery'; ...@@ -2,7 +2,8 @@ import $ from 'jquery';
class RefSelectDropdown { class RefSelectDropdown {
constructor($dropdownButton, availableRefs) { constructor($dropdownButton, availableRefs) {
const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML); const availableRefsValue =
availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({ $dropdownButton.glDropdown({
data: availableRefsValue, data: availableRefsValue,
filterable: true, filterable: true,
...@@ -29,7 +30,7 @@ class RefSelectDropdown { ...@@ -29,7 +30,7 @@ class RefSelectDropdown {
const $fieldInput = $(`input[name="${$dropdownButton.data('fieldName')}"]`, $dropdownContainer); const $fieldInput = $(`input[name="${$dropdownButton.data('fieldName')}"]`, $dropdownContainer);
const $filterInput = $('input[type="search"]', $dropdownContainer); const $filterInput = $('input[type="search"]', $dropdownContainer);
$filterInput.on('keyup', (e) => { $filterInput.on('keyup', e => {
const keyCode = e.keyCode || e.which; const keyCode = e.keyCode || e.which;
if (keyCode !== 13) return; if (keyCode !== 13) return;
......
...@@ -3,10 +3,14 @@ import { __ } from './locale'; ...@@ -3,10 +3,14 @@ import { __ } from './locale';
function expandSection($section) { function expandSection($section) {
$section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Collapse')); $section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Collapse'));
$section.find('.settings-content').off('scroll.expandSection').scrollTop(0); $section
.find('.settings-content')
.off('scroll.expandSection')
.scrollTop(0);
$section.addClass('expanded'); $section.addClass('expanded');
if (!$section.hasClass('no-animate')) { if (!$section.hasClass('no-animate')) {
$section.addClass('animating') $section
.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating')); .one('animationend.animateSection', () => $section.removeClass('animating'));
} }
} }
...@@ -16,7 +20,8 @@ function closeSection($section) { ...@@ -16,7 +20,8 @@ function closeSection($section) {
$section.find('.settings-content').on('scroll.expandSection', () => expandSection($section)); $section.find('.settings-content').on('scroll.expandSection', () => expandSection($section));
$section.removeClass('expanded'); $section.removeClass('expanded');
if (!$section.hasClass('no-animate')) { if (!$section.hasClass('no-animate')) {
$section.addClass('animating') $section
.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating')); .one('animationend.animateSection', () => $section.removeClass('animating'));
} }
} }
......
...@@ -10,8 +10,10 @@ import syntaxHighlight from './syntax_highlight'; ...@@ -10,8 +10,10 @@ import syntaxHighlight from './syntax_highlight';
const WRAPPER = '<div class="diff-content"></div>'; const WRAPPER = '<div class="diff-content"></div>';
const LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>'; const LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
const ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>'; const ERROR_HTML =
const COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link">Click to expand it.</button></div>'; '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
const COLLAPSED_HTML =
'<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link">Click to expand it.</button></div>';
export default class SingleFileDiff { export default class SingleFileDiff {
constructor(file) { constructor(file) {
...@@ -23,23 +25,36 @@ export default class SingleFileDiff { ...@@ -23,23 +25,36 @@ export default class SingleFileDiff {
this.isOpen = !this.diffForPath; this.isOpen = !this.diffForPath;
if (this.diffForPath) { if (this.diffForPath) {
this.collapsedContent = this.content; this.collapsedContent = this.content;
this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide(); this.loadingContent = $(WRAPPER)
.addClass('loading')
.html(LOADING_HTML)
.hide();
this.content = null; this.content = null;
this.collapsedContent.after(this.loadingContent); this.collapsedContent.after(this.loadingContent);
this.$toggleIcon.addClass('fa-caret-right'); this.$toggleIcon.addClass('fa-caret-right');
} else { } else {
this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide(); this.collapsedContent = $(WRAPPER)
.html(COLLAPSED_HTML)
.hide();
this.content.after(this.collapsedContent); this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down'); this.$toggleIcon.addClass('fa-caret-down');
} }
$('.js-file-title, .click-to-expand', this.file).on('click', (function (e) { $('.js-file-title, .click-to-expand', this.file).on(
this.toggleDiff($(e.target)); 'click',
}).bind(this)); function(e) {
this.toggleDiff($(e.target));
}.bind(this),
);
} }
toggleDiff($target, cb) { toggleDiff($target, cb) {
if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return; if (
!$target.hasClass('js-file-title') &&
!$target.hasClass('click-to-expand') &&
!$target.hasClass('diff-toggle-caret')
)
return;
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) { if (!this.isOpen && !this.hasError) {
this.content.hide(); this.content.hide();
...@@ -65,7 +80,8 @@ export default class SingleFileDiff { ...@@ -65,7 +80,8 @@ export default class SingleFileDiff {
this.collapsedContent.hide(); this.collapsedContent.hide();
this.loadingContent.show(); this.loadingContent.show();
axios.get(this.diffForPath) axios
.get(this.diffForPath)
.then(({ data }) => { .then(({ data }) => {
this.loadingContent.hide(); this.loadingContent.hide();
if (data.html) { if (data.html) {
......
...@@ -93,7 +93,9 @@ export default class SmartInterval { ...@@ -93,7 +93,9 @@ export default class SmartInterval {
destroy() { destroy() {
this.cancel(); this.cancel();
document.removeEventListener('visibilitychange', this.handleVisibilityChange); document.removeEventListener('visibilitychange', this.handleVisibilityChange);
$(document).off('visibilitychange').off('beforeunload'); $(document)
.off('visibilitychange')
.off('beforeunload');
} }
/* private */ /* private */
...@@ -111,11 +113,12 @@ export default class SmartInterval { ...@@ -111,11 +113,12 @@ export default class SmartInterval {
triggerCallback() { triggerCallback() {
this.isLoading = true; this.isLoading = true;
this.cfg.callback() this.cfg
.callback()
.then(() => { .then(() => {
this.isLoading = false; this.isLoading = false;
}) })
.catch((err) => { .catch(err => {
this.isLoading = false; this.isLoading = false;
throw err; throw err;
}); });
...@@ -134,9 +137,9 @@ export default class SmartInterval { ...@@ -134,9 +137,9 @@ export default class SmartInterval {
handleVisibilityChange(e) { handleVisibilityChange(e) {
this.state.pageVisibility = e.target.visibilityState; this.state.pageVisibility = e.target.visibilityState;
const intervalAction = this.isPageVisible() ? const intervalAction = this.isPageVisible()
this.onVisibilityVisible : ? this.onVisibilityVisible
this.onVisibilityHidden; : this.onVisibilityHidden;
intervalAction.apply(this); intervalAction.apply(this);
} }
...@@ -162,7 +165,9 @@ export default class SmartInterval { ...@@ -162,7 +165,9 @@ export default class SmartInterval {
this.setCurrentInterval(nextInterval); this.setCurrentInterval(nextInterval);
} }
isPageVisible() { return this.state.pageVisibility === 'visible'; } isPageVisible() {
return this.state.pageVisibility === 'visible';
}
stopTimer() { stopTimer() {
const { state } = this; const { state } = this;
...@@ -170,4 +175,3 @@ export default class SmartInterval { ...@@ -170,4 +175,3 @@ export default class SmartInterval {
state.intervalId = window.clearInterval(state.intervalId); state.intervalId = window.clearInterval(state.intervalId);
} }
} }
...@@ -11,10 +11,14 @@ export default class Star { ...@@ -11,10 +11,14 @@ export default class Star {
const $starSpan = $this.find('span'); const $starSpan = $this.find('span');
const $startIcon = $this.find('svg'); const $startIcon = $this.find('svg');
axios.post($this.data('endpoint')) axios
.post($this.data('endpoint'))
.then(({ data }) => { .then(({ data }) => {
const isStarred = $starSpan.hasClass('starred'); const isStarred = $starSpan.hasClass('starred');
$this.parent().find('.star-count').text(data.star_count); $this
.parent()
.find('.star-count')
.text(data.star_count);
if (isStarred) { if (isStarred) {
$starSpan.removeClass('starred').text(s__('StarProject|Star')); $starSpan.removeClass('starred').text(s__('StarProject|Star'));
......
...@@ -26,7 +26,11 @@ export default class TaskList { ...@@ -26,7 +26,11 @@ export default class TaskList {
// Prevent duplicate event bindings // Prevent duplicate event bindings
this.disable(); this.disable();
$(`${this.selector} .js-task-list-container`).taskList('enable'); $(`${this.selector} .js-task-list-container`).taskList('enable');
$(document).on('tasklist:changed', `${this.selector} .js-task-list-container`, this.update.bind(this)); $(document).on(
'tasklist:changed',
`${this.selector} .js-task-list-container`,
this.update.bind(this),
);
} }
disable() { disable() {
...@@ -41,7 +45,8 @@ export default class TaskList { ...@@ -41,7 +45,8 @@ export default class TaskList {
[this.fieldName]: $target.val(), [this.fieldName]: $target.val(),
}; };
return axios.patch($target.data('updateUrl') || $('form.js-issuable-update').attr('action'), patchData) return axios
.patch($target.data('updateUrl') || $('form.js-issuable-update').attr('action'), patchData)
.then(({ data }) => this.onSuccess(data)) .then(({ data }) => this.onSuccess(data))
.catch(err => this.onError(err)); .catch(err => this.onError(err));
} }
......
...@@ -31,12 +31,18 @@ export default class IssuableTemplateSelector extends TemplateSelector { ...@@ -31,12 +31,18 @@ export default class IssuableTemplateSelector extends TemplateSelector {
requestFile(query) { requestFile(query) {
this.startLoadingSpinner(); this.startLoadingSpinner();
Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => { Api.issueTemplate(
this.currentTemplate = currentTemplate; this.namespacePath,
this.stopLoadingSpinner(); this.projectPath,
if (err) return; // Error handled by global AJAX error handler query.name,
this.setInputValueToTemplateContent(); this.issuableType,
}); (err, currentTemplate) => {
this.currentTemplate = currentTemplate;
this.stopLoadingSpinner();
if (err) return; // Error handled by global AJAX error handler
this.setInputValueToTemplateContent();
},
);
return; return;
} }
......
...@@ -4,10 +4,14 @@ import * as fit from 'xterm/lib/addons/fit/fit'; ...@@ -4,10 +4,14 @@ import * as fit from 'xterm/lib/addons/fit/fit';
export default class GLTerminal { export default class GLTerminal {
constructor(options = {}) { constructor(options = {}) {
this.options = Object.assign({}, { this.options = Object.assign(
cursorBlink: true, {},
screenKeys: true, {
}, options); cursorBlink: true,
screenKeys: true,
},
options,
);
this.container = document.querySelector(options.selector); this.container = document.querySelector(options.selector);
......
...@@ -4,15 +4,43 @@ function simulateEvent(el, type, options = {}) { ...@@ -4,15 +4,43 @@ function simulateEvent(el, type, options = {}) {
if (/^mouse/.test(type)) { if (/^mouse/.test(type)) {
event = el.ownerDocument.createEvent('MouseEvents'); event = el.ownerDocument.createEvent('MouseEvents');
event.initMouseEvent(type, true, true, el.ownerDocument.defaultView, event.initMouseEvent(
options.button, options.screenX, options.screenY, options.clientX, options.clientY, type,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); true,
true,
el.ownerDocument.defaultView,
options.button,
options.screenX,
options.screenY,
options.clientX,
options.clientY,
options.ctrlKey,
options.altKey,
options.shiftKey,
options.metaKey,
options.button,
el,
);
} else { } else {
event = el.ownerDocument.createEvent('CustomEvent'); event = el.ownerDocument.createEvent('CustomEvent');
event.initCustomEvent(type, true, true, el.ownerDocument.defaultView, event.initCustomEvent(
options.button, options.screenX, options.screenY, options.clientX, options.clientY, type,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); true,
true,
el.ownerDocument.defaultView,
options.button,
options.screenX,
options.screenY,
options.clientX,
options.clientY,
options.ctrlKey,
options.altKey,
options.shiftKey,
options.metaKey,
options.button,
el,
);
event.dataTransfer = { event.dataTransfer = {
data: {}, data: {},
...@@ -37,14 +65,16 @@ function simulateEvent(el, type, options = {}) { ...@@ -37,14 +65,16 @@ function simulateEvent(el, type, options = {}) {
} }
function isLast(target) { function isLast(target) {
const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; const el =
typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
const { children } = el; const { children } = el;
return children.length - 1 === target.index; return children.length - 1 === target.index;
} }
function getTarget(target) { function getTarget(target) {
const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; const el =
typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
const { children } = el; const { children } = el;
return ( return (
...@@ -58,13 +88,13 @@ function getTarget(target) { ...@@ -58,13 +88,13 @@ function getTarget(target) {
function getRect(el) { function getRect(el) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const width = rect.right - rect.left; const width = rect.right - rect.left;
const height = (rect.bottom - rect.top) + 10; const height = rect.bottom - rect.top + 10;
return { return {
x: rect.left, x: rect.left,
y: rect.top, y: rect.top,
cx: rect.left + (width / 2), cx: rect.left + width / 2,
cy: rect.top + (height / 2), cy: rect.top + height / 2,
w: width, w: width,
h: height, h: height,
hw: width / 2, hw: width / 2,
...@@ -112,8 +142,8 @@ export default function simulateDrag(options) { ...@@ -112,8 +142,8 @@ export default function simulateDrag(options) {
const dragInterval = setInterval(() => { const dragInterval = setInterval(() => {
const progress = (new Date().getTime() - startTime) / duration; const progress = (new Date().getTime() - startTime) / duration;
const x = (fromRect.cx + ((toRect.cx - fromRect.cx) * progress)); const x = fromRect.cx + (toRect.cx - fromRect.cx) * progress;
const y = (fromRect.cy + ((toRect.cy - fromRect.cy) * progress)); const y = fromRect.cy + (toRect.cy - fromRect.cy) * progress;
const overEl = fromEl.ownerDocument.elementFromPoint(x, y); const overEl = fromEl.ownerDocument.elementFromPoint(x, y);
simulateEvent(overEl, 'mousemove', { simulateEvent(overEl, 'mousemove', {
......
...@@ -12,7 +12,7 @@ export default function simulateInput(target, text) { ...@@ -12,7 +12,7 @@ export default function simulateInput(target, text) {
} }
if (text.length > 0) { if (text.length > 0) {
Array.prototype.forEach.call(text, (char) => { Array.prototype.forEach.call(text, char => {
input.value += char; input.value += char;
triggerEvents(input); triggerEvents(input);
}); });
......
...@@ -49,7 +49,7 @@ function onToggleClicked(toggle, input, clickCallback) { ...@@ -49,7 +49,7 @@ function onToggleClicked(toggle, input, clickCallback) {
export default function setupToggleButtons(container, clickCallback = () => {}) { export default function setupToggleButtons(container, clickCallback = () => {}) {
const toggles = container.querySelectorAll('.js-project-feature-toggle'); const toggles = container.querySelectorAll('.js-project-feature-toggle');
toggles.forEach((toggle) => { toggles.forEach(toggle => {
const input = toggle.querySelector('.js-project-feature-toggle-input'); const input = toggle.querySelector('.js-project-feature-toggle-input');
const isOn = convertPermissionToBoolean(input.value); const isOn = convertPermissionToBoolean(input.value);
......
...@@ -8,7 +8,7 @@ export default class TreeView { ...@@ -8,7 +8,7 @@ export default class TreeView {
this.initKeyNav(); this.initKeyNav();
// Code browser tree slider // Code browser tree slider
// Make the entire tree-item row clickable, but not if clicking another link (like a commit message) // Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
$(".tree-content-holder .tree-item").on('click', function(e) { $('.tree-content-holder .tree-item').on('click', function(e) {
var $clickedEl, path; var $clickedEl, path;
$clickedEl = $(e.target); $clickedEl = $(e.target);
path = $('.tree-item-file-name a', this).attr('href'); path = $('.tree-item-file-name a', this).attr('href');
...@@ -27,33 +27,33 @@ export default class TreeView { ...@@ -27,33 +27,33 @@ export default class TreeView {
initKeyNav() { initKeyNav() {
var li, liSelected; var li, liSelected;
li = $("tr.tree-item"); li = $('tr.tree-item');
liSelected = null; liSelected = null;
return $('body').keydown(function(e) { return $('body').keydown(function(e) {
var next, path; var next, path;
if ($("input:focus").length > 0 && (e.which === 38 || e.which === 40)) { if ($('input:focus').length > 0 && (e.which === 38 || e.which === 40)) {
return false; return false;
} }
if (e.which === 40) { if (e.which === 40) {
if (liSelected) { if (liSelected) {
next = liSelected.next(); next = liSelected.next();
if (next.length > 0) { if (next.length > 0) {
liSelected.removeClass("selected"); liSelected.removeClass('selected');
liSelected = next.addClass("selected"); liSelected = next.addClass('selected');
} }
} else { } else {
liSelected = li.eq(0).addClass("selected"); liSelected = li.eq(0).addClass('selected');
} }
return $(liSelected).focus(); return $(liSelected).focus();
} else if (e.which === 38) { } else if (e.which === 38) {
if (liSelected) { if (liSelected) {
next = liSelected.prev(); next = liSelected.prev();
if (next.length > 0) { if (next.length > 0) {
liSelected.removeClass("selected"); liSelected.removeClass('selected');
liSelected = next.addClass("selected"); liSelected = next.addClass('selected');
} }
} else { } else {
liSelected = li.last().addClass("selected"); liSelected = li.last().addClass('selected');
} }
return $(liSelected).focus(); return $(liSelected).focus();
} else if (e.which === 13) { } else if (e.which === 13) {
......
...@@ -49,7 +49,7 @@ export default class U2FAuthenticate { ...@@ -49,7 +49,7 @@ export default class U2FAuthenticate {
start() { start() {
return importU2FLibrary() return importU2FLibrary()
.then((utils) => { .then(utils => {
this.u2fUtils = utils; this.u2fUtils = utils;
this.renderInProgress(); this.renderInProgress();
}) })
...@@ -57,14 +57,19 @@ export default class U2FAuthenticate { ...@@ -57,14 +57,19 @@ export default class U2FAuthenticate {
} }
authenticate() { authenticate() {
return this.u2fUtils.sign(this.appId, this.challenge, this.signRequests, return this.u2fUtils.sign(
(response) => { this.appId,
this.challenge,
this.signRequests,
response => {
if (response.errorCode) { if (response.errorCode) {
const error = new U2FError(response.errorCode, 'authenticate'); const error = new U2FError(response.errorCode, 'authenticate');
return this.renderError(error); return this.renderError(error);
} }
return this.renderAuthenticated(JSON.stringify(response)); return this.renderAuthenticated(JSON.stringify(response));
}, 10); },
10,
);
} }
renderTemplate(name, params) { renderTemplate(name, params) {
...@@ -99,5 +104,4 @@ export default class U2FAuthenticate { ...@@ -99,5 +104,4 @@ export default class U2FAuthenticate {
this.container[0].classList.add('hidden'); this.container[0].classList.add('hidden');
this.fallbackUI.classList.remove('hidden'); this.fallbackUI.classList.remove('hidden');
} }
} }
...@@ -34,7 +34,7 @@ export default class U2FRegister { ...@@ -34,7 +34,7 @@ export default class U2FRegister {
start() { start() {
return importU2FLibrary() return importU2FLibrary()
.then((utils) => { .then(utils => {
this.u2fUtils = utils; this.u2fUtils = utils;
this.renderSetup(); this.renderSetup();
}) })
...@@ -42,14 +42,19 @@ export default class U2FRegister { ...@@ -42,14 +42,19 @@ export default class U2FRegister {
} }
register() { register() {
return this.u2fUtils.register(this.appId, this.registerRequests, this.signRequests, return this.u2fUtils.register(
(response) => { this.appId,
this.registerRequests,
this.signRequests,
response => {
if (response.errorCode) { if (response.errorCode) {
const error = new U2FError(response.errorCode, 'register'); const error = new U2FError(response.errorCode, 'register');
return this.renderError(error); return this.renderError(error);
} }
return this.renderRegistered(JSON.stringify(response)); return this.renderRegistered(JSON.stringify(response));
}, 10); },
10,
);
} }
renderTemplate(name, params) { renderTemplate(name, params) {
......
...@@ -19,11 +19,10 @@ function getChromeVersion(userAgent) { ...@@ -19,11 +19,10 @@ function getChromeVersion(userAgent) {
export function canInjectU2fApi(userAgent) { export function canInjectU2fApi(userAgent) {
const isSupportedChrome = isChrome(userAgent) && getChromeVersion(userAgent) >= 41; const isSupportedChrome = isChrome(userAgent) && getChromeVersion(userAgent) >= 41;
const isSupportedOpera = isOpera(userAgent) && getOperaVersion(userAgent) >= 40; const isSupportedOpera = isOpera(userAgent) && getOperaVersion(userAgent) >= 40;
const isMobile = ( const isMobile =
userAgent.indexOf('droid') >= 0 || userAgent.indexOf('droid') >= 0 ||
userAgent.indexOf('CriOS') >= 0 || userAgent.indexOf('CriOS') >= 0 ||
/\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
);
return (isSupportedChrome || isSupportedOpera) && !isMobile; return (isSupportedChrome || isSupportedOpera) && !isMobile;
} }
......
...@@ -4,13 +4,17 @@ import Api from './api'; ...@@ -4,13 +4,17 @@ import Api from './api';
export default () => { export default () => {
$('#js-project-dropdown').glDropdown({ $('#js-project-dropdown').glDropdown({
data: (term, callback) => { data: (term, callback) => {
Api.projects(term, { Api.projects(
order_by: 'last_activity_at', term,
}, (data) => { {
callback(data); order_by: 'last_activity_at',
}); },
data => {
callback(data);
},
);
}, },
text: project => (project.name_with_namespace || project.name), text: project => project.name_with_namespace || project.name,
selectable: true, selectable: true,
fieldName: 'author_id', fieldName: 'author_id',
filterable: true, filterable: true,
...@@ -18,6 +22,6 @@ export default () => { ...@@ -18,6 +22,6 @@ export default () => {
fields: ['name_with_namespace'], fields: ['name_with_namespace'],
}, },
id: data => data.id, id: data => data.id,
isSelected: data => (data.id === 2), isSelected: data => data.id === 2,
}); });
}; };
...@@ -4,7 +4,7 @@ import Flash, { hideFlash } from './flash'; ...@@ -4,7 +4,7 @@ import Flash, { hideFlash } from './flash';
import { convertPermissionToBoolean } from './lib/utils/common_utils'; import { convertPermissionToBoolean } from './lib/utils/common_utils';
export default () => { export default () => {
$('body').on('click', '.js-usage-consent-action', (e) => { $('body').on('click', '.js-usage-consent-action', e => {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); // overwrite rails listener e.stopImmediatePropagation(); // overwrite rails listener
...@@ -18,7 +18,8 @@ export default () => { ...@@ -18,7 +18,8 @@ export default () => {
const hideConsentMessage = () => hideFlash(document.querySelector('.ping-consent-message')); const hideConsentMessage = () => hideFlash(document.querySelector('.ping-consent-message'));
axios.put(url, data) axios
.put(url, data)
.then(() => { .then(() => {
hideConsentMessage(); hideConsentMessage();
}) })
......
...@@ -15,8 +15,8 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -15,8 +15,8 @@ function UsersSelect(currentUser, els, options = {}) {
var $els; var $els;
this.users = this.users.bind(this); this.users = this.users.bind(this);
this.user = this.user.bind(this); this.user = this.user.bind(this);
this.usersPath = "/autocomplete/users.json"; this.usersPath = '/autocomplete/users.json';
this.userPath = "/autocomplete/users/:id.json"; this.userPath = '/autocomplete/users/:id.json';
if (currentUser != null) { if (currentUser != null) {
if (typeof currentUser === 'object') { if (typeof currentUser === 'object') {
this.currentUser = currentUser; this.currentUser = currentUser;
...@@ -33,156 +33,180 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -33,156 +33,180 @@ function UsersSelect(currentUser, els, options = {}) {
$els = $('.js-user-search'); $els = $('.js-user-search');
} }
$els.each((function(_this) { $els.each(
return function(i, dropdown) { (function(_this) {
var options = {}; return function(i, dropdown) {
var $block, $collapsedSidebar, $dropdown, $loading, $selectbox, $value, abilityName, assignTo, assigneeTemplate, collapsedAssigneeTemplate, defaultLabel, defaultNullUser, firstUser, issueURL, selectedId, selectedIdDefault, showAnyUser, showNullUser, showMenuAbove; var options = {};
$dropdown = $(dropdown); var $block,
options.projectId = $dropdown.data('projectId'); $collapsedSidebar,
options.groupId = $dropdown.data('groupId'); $dropdown,
options.showCurrentUser = $dropdown.data('currentUser'); $loading,
options.todoFilter = $dropdown.data('todoFilter'); $selectbox,
options.todoStateFilter = $dropdown.data('todoStateFilter'); $value,
showNullUser = $dropdown.data('nullUser'); abilityName,
defaultNullUser = $dropdown.data('nullUserDefault'); assignTo,
showMenuAbove = $dropdown.data('showMenuAbove'); assigneeTemplate,
showAnyUser = $dropdown.data('anyUser'); collapsedAssigneeTemplate,
firstUser = $dropdown.data('firstUser'); defaultLabel,
options.authorId = $dropdown.data('authorId'); defaultNullUser,
defaultLabel = $dropdown.data('defaultLabel'); firstUser,
issueURL = $dropdown.data('issueUpdate'); issueURL,
$selectbox = $dropdown.closest('.selectbox'); selectedId,
$block = $selectbox.closest('.block'); selectedIdDefault,
abilityName = $dropdown.data('abilityName'); showAnyUser,
$value = $block.find('.value'); showNullUser,
$collapsedSidebar = $block.find('.sidebar-collapsed-user'); showMenuAbove;
$loading = $block.find('.block-loading').fadeOut(); $dropdown = $(dropdown);
selectedIdDefault = (defaultNullUser && showNullUser) ? 0 : null; options.projectId = $dropdown.data('projectId');
selectedId = $dropdown.data('selected'); options.groupId = $dropdown.data('groupId');
options.showCurrentUser = $dropdown.data('currentUser');
if (selectedId === undefined) { options.todoFilter = $dropdown.data('todoFilter');
selectedId = selectedIdDefault; options.todoStateFilter = $dropdown.data('todoStateFilter');
} showNullUser = $dropdown.data('nullUser');
defaultNullUser = $dropdown.data('nullUserDefault');
const assignYourself = function () { showMenuAbove = $dropdown.data('showMenuAbove');
const unassignedSelected = $dropdown.closest('.selectbox') showAnyUser = $dropdown.data('anyUser');
.find(`input[name='${$dropdown.data('fieldName')}'][value=0]`); firstUser = $dropdown.data('firstUser');
options.authorId = $dropdown.data('authorId');
if (unassignedSelected) { defaultLabel = $dropdown.data('defaultLabel');
unassignedSelected.remove(); issueURL = $dropdown.data('issueUpdate');
$selectbox = $dropdown.closest('.selectbox');
$block = $selectbox.closest('.block');
abilityName = $dropdown.data('abilityName');
$value = $block.find('.value');
$collapsedSidebar = $block.find('.sidebar-collapsed-user');
$loading = $block.find('.block-loading').fadeOut();
selectedIdDefault = defaultNullUser && showNullUser ? 0 : null;
selectedId = $dropdown.data('selected');
if (selectedId === undefined) {
selectedId = selectedIdDefault;
} }
// Save current selected user to the DOM const assignYourself = function() {
const input = document.createElement('input'); const unassignedSelected = $dropdown
input.type = 'hidden'; .closest('.selectbox')
input.name = $dropdown.data('fieldName'); .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
const currentUserInfo = $dropdown.data('currentUserInfo'); if (unassignedSelected) {
unassignedSelected.remove();
if (currentUserInfo) { }
input.value = currentUserInfo.id;
input.dataset.meta = _.escape(currentUserInfo.name);
} else if (_this.currentUser) {
input.value = _this.currentUser.id;
}
if ($selectbox) {
$dropdown.parent().before(input);
} else {
$dropdown.after(input);
}
};
if ($block[0]) {
$block[0].addEventListener('assignYourself', assignYourself);
}
const getSelectedUserInputs = function() {
return $selectbox
.find(`input[name="${$dropdown.data('fieldName')}"]`);
};
const getSelected = function() { // Save current selected user to the DOM
return getSelectedUserInputs() const input = document.createElement('input');
.map((index, input) => parseInt(input.value, 10)) input.type = 'hidden';
.get(); input.name = $dropdown.data('fieldName');
};
const checkMaxSelect = function() { const currentUserInfo = $dropdown.data('currentUserInfo');
const maxSelect = $dropdown.data('maxSelect');
if (maxSelect) {
const selected = getSelected();
if (selected.length > maxSelect) { if (currentUserInfo) {
const firstSelectedId = selected[0]; input.value = currentUserInfo.id;
const firstSelected = $dropdown.closest('.selectbox') input.dataset.meta = _.escape(currentUserInfo.name);
.find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`); } else if (_this.currentUser) {
input.value = _this.currentUser.id;
}
firstSelected.remove(); if ($selectbox) {
emitSidebarEvent('sidebar.removeAssignee', { $dropdown.parent().before(input);
id: firstSelectedId, } else {
}); $dropdown.after(input);
} }
} };
};
const getMultiSelectDropdownTitle = function(selectedUser, isSelected) { if ($block[0]) {
const selectedUsers = getSelected() $block[0].addEventListener('assignYourself', assignYourself);
.filter(u => u !== 0);
const firstUser = getSelectedUserInputs()
.map((index, input) => ({
name: input.dataset.meta,
value: parseInt(input.value, 10),
}))
.filter(u => u.id !== 0)
.get(0);
if (selectedUsers.length === 0) {
return 'Unassigned';
} else if (selectedUsers.length === 1) {
return firstUser.name;
} else if (isSelected) {
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
return `${selectedUser.name} + ${otherSelected.length} more`;
} else {
return `${firstUser.name} + ${selectedUsers.length - 1} more`;
} }
};
$('.assign-to-me-link').on('click', (e) => { const getSelectedUserInputs = function() {
e.preventDefault(); return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`);
$(e.currentTarget).hide(); };
const getSelected = function() {
return getSelectedUserInputs()
.map((index, input) => parseInt(input.value, 10))
.get();
};
const checkMaxSelect = function() {
const maxSelect = $dropdown.data('maxSelect');
if (maxSelect) {
const selected = getSelected();
if (selected.length > maxSelect) {
const firstSelectedId = selected[0];
const firstSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
firstSelected.remove();
emitSidebarEvent('sidebar.removeAssignee', {
id: firstSelectedId,
});
}
}
};
const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
const selectedUsers = getSelected().filter(u => u !== 0);
const firstUser = getSelectedUserInputs()
.map((index, input) => ({
name: input.dataset.meta,
value: parseInt(input.value, 10),
}))
.filter(u => u.id !== 0)
.get(0);
if (selectedUsers.length === 0) {
return 'Unassigned';
} else if (selectedUsers.length === 1) {
return firstUser.name;
} else if (isSelected) {
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
return `${selectedUser.name} + ${otherSelected.length} more`;
} else {
return `${firstUser.name} + ${selectedUsers.length - 1} more`;
}
};
if ($dropdown.data('multiSelect')) { $('.assign-to-me-link').on('click', e => {
assignYourself(); e.preventDefault();
checkMaxSelect(); $(e.currentTarget).hide();
const currentUserInfo = $dropdown.data('currentUserInfo'); if ($dropdown.data('multiSelect')) {
$dropdown.find('.dropdown-toggle-text').text(getMultiSelectDropdownTitle(currentUserInfo)).removeClass('is-default'); assignYourself();
} else { checkMaxSelect();
const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
$input.val(gon.current_user_id); const currentUserInfo = $dropdown.data('currentUserInfo');
selectedId = $input.val(); $dropdown
$dropdown.find('.dropdown-toggle-text').text(gon.current_user_fullname).removeClass('is-default'); .find('.dropdown-toggle-text')
} .text(getMultiSelectDropdownTitle(currentUserInfo))
}); .removeClass('is-default');
} else {
$block.on('click', '.js-assign-yourself', (e) => { const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
e.preventDefault(); $input.val(gon.current_user_id);
return assignTo(_this.currentUser.id); selectedId = $input.val();
}); $dropdown
.find('.dropdown-toggle-text')
assignTo = function(selected) { .text(gon.current_user_fullname)
var data; .removeClass('is-default');
data = {}; }
data[abilityName] = {}; });
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn(); $block.on('click', '.js-assign-yourself', e => {
$dropdown.trigger('loading.gl.dropdown'); e.preventDefault();
return assignTo(_this.currentUser.id);
return axios.put(issueURL, data) });
.then(({ data }) => {
assignTo = function(selected) {
var data;
data = {};
data[abilityName] = {};
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return axios.put(issueURL, data).then(({ data }) => {
var user, tooltipTitle; var user, tooltipTitle;
$dropdown.trigger('loaded.gl.dropdown'); $dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut(); $loading.fadeOut();
...@@ -190,14 +214,14 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -190,14 +214,14 @@ function UsersSelect(currentUser, els, options = {}) {
user = { user = {
name: data.assignee.name, name: data.assignee.name,
username: data.assignee.username, username: data.assignee.username,
avatar: data.assignee.avatar_url avatar: data.assignee.avatar_url,
}; };
tooltipTitle = _.escape(user.name); tooltipTitle = _.escape(user.name);
} else { } else {
user = { user = {
name: 'Unassigned', name: 'Unassigned',
username: '', username: '',
avatar: '' avatar: '',
}; };
tooltipTitle = __('Assignee'); tooltipTitle = __('Assignee');
} }
...@@ -205,319 +229,341 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -205,319 +229,341 @@ function UsersSelect(currentUser, els, options = {}) {
$collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle'); $collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
return $collapsedSidebar.html(collapsedAssigneeTemplate(user)); return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
}); });
}; };
collapsedAssigneeTemplate = _.template('<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>'); collapsedAssigneeTemplate = _.template(
assigneeTemplate = _.template('<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>'); '<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
return $dropdown.glDropdown({ );
showMenuAbove: showMenuAbove, assigneeTemplate = _.template(
data: function(term, callback) { '<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>',
return _this.users(term, options, function(users) { );
// GitLabDropdownFilter returns this.instance return $dropdown.glDropdown({
// GitLabDropdownRemote returns this.options.instance showMenuAbove: showMenuAbove,
const glDropdown = this.instance || this.options.instance; data: function(term, callback) {
glDropdown.options.processData(term, users, callback); return _this.users(
}.bind(this)); term,
}, options,
processData: function(term, data, callback) { function(users) {
let users = data; // GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
// Only show assigned user list when there is no search term const glDropdown = this.instance || this.options.instance;
if ($dropdown.hasClass('js-multiselect') && term.length === 0) { glDropdown.options.processData(term, users, callback);
const selectedInputs = getSelectedUserInputs(); }.bind(this),
);
// Potential duplicate entries when dealing with issue board },
// because issue board is also managed by vue processData: function(term, data, callback) {
const selectedUsers = _.uniq(selectedInputs, false, a => a.value) let users = data;
.filter((input) => {
const userId = parseInt(input.value, 10); // Only show assigned user list when there is no search term
const inUsersArray = users.find(u => u.id === userId); if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
const selectedInputs = getSelectedUserInputs();
return !inUsersArray && userId !== 0;
}) // Potential duplicate entries when dealing with issue board
.map((input) => { // because issue board is also managed by vue
const userId = parseInt(input.value, 10); const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
const { avatarUrl, avatar_url, name, username } = input.dataset; .filter(input => {
return { const userId = parseInt(input.value, 10);
avatar_url: avatarUrl || avatar_url, const inUsersArray = users.find(u => u.id === userId);
id: userId,
name, return !inUsersArray && userId !== 0;
username, })
}; .map(input => {
}); const userId = parseInt(input.value, 10);
const { avatarUrl, avatar_url, name, username } = input.dataset;
return {
avatar_url: avatarUrl || avatar_url,
id: userId,
name,
username,
};
});
users = data.concat(selectedUsers); users = data.concat(selectedUsers);
} }
let anyUser; let anyUser;
let index; let index;
let len; let len;
let name; let name;
let obj; let obj;
let showDivider; let showDivider;
if (term.length === 0) { if (term.length === 0) {
showDivider = 0; showDivider = 0;
if (firstUser) { if (firstUser) {
// Move current user to the front of the list // Move current user to the front of the list
for (index = 0, len = users.length; index < len; index += 1) { for (index = 0, len = users.length; index < len; index += 1) {
obj = users[index]; obj = users[index];
if (obj.username === firstUser) { if (obj.username === firstUser) {
users.splice(index, 1); users.splice(index, 1);
users.unshift(obj); users.unshift(obj);
break; break;
}
} }
} }
} if (showNullUser) {
if (showNullUser) { showDivider += 1;
showDivider += 1; users.unshift({
users.unshift({ beforeDivider: true,
beforeDivider: true, name: 'Unassigned',
name: 'Unassigned', id: 0,
id: 0 });
}); }
} if (showAnyUser) {
if (showAnyUser) { showDivider += 1;
showDivider += 1; name = showAnyUser;
name = showAnyUser; if (name === true) {
if (name === true) { name = 'Any User';
name = 'Any User'; }
anyUser = {
beforeDivider: true,
name: name,
id: null,
};
users.unshift(anyUser);
} }
anyUser = {
beforeDivider: true,
name: name,
id: null
};
users.unshift(anyUser);
}
if (showDivider) { if (showDivider) {
users.splice(showDivider, 0, 'divider'); users.splice(showDivider, 0, 'divider');
} }
if ($dropdown.hasClass('js-multiselect')) { if ($dropdown.hasClass('js-multiselect')) {
const selected = getSelected().filter(i => i !== 0); const selected = getSelected().filter(i => i !== 0);
if (selected.length > 0) { if (selected.length > 0) {
if ($dropdown.data('dropdownHeader')) { if ($dropdown.data('dropdownHeader')) {
showDivider += 1; showDivider += 1;
users.splice(showDivider, 0, { users.splice(showDivider, 0, {
header: $dropdown.data('dropdownHeader'), header: $dropdown.data('dropdownHeader'),
}); });
} }
const selectedUsers = users const selectedUsers = users
.filter(u => selected.indexOf(u.id) !== -1) .filter(u => selected.indexOf(u.id) !== -1)
.sort((a, b) => a.name > b.name); .sort((a, b) => a.name > b.name);
users = users.filter(u => selected.indexOf(u.id) === -1); users = users.filter(u => selected.indexOf(u.id) === -1);
selectedUsers.forEach((selectedUser) => { selectedUsers.forEach(selectedUser => {
showDivider += 1; showDivider += 1;
users.splice(showDivider, 0, selectedUser); users.splice(showDivider, 0, selectedUser);
}); });
users.splice(showDivider + 1, 0, 'divider'); users.splice(showDivider + 1, 0, 'divider');
}
} }
} }
}
callback(users); callback(users);
if (showMenuAbove) { if (showMenuAbove) {
$dropdown.data('glDropdown').positionMenuAbove(); $dropdown.data('glDropdown').positionMenuAbove();
} }
}, },
filterable: true, filterable: true,
filterRemote: true, filterRemote: true,
search: { search: {
fields: ['name', 'username'] fields: ['name', 'username'],
}, },
selectable: true, selectable: true,
fieldName: $dropdown.data('fieldName'), fieldName: $dropdown.data('fieldName'),
toggleLabel: function(selected, el, glDropdown) { toggleLabel: function(selected, el, glDropdown) {
const inputValue = glDropdown.filterInput.val(); const inputValue = glDropdown.filterInput.val();
if (this.multiSelect && inputValue === '') { if (this.multiSelect && inputValue === '') {
// Remove non-users from the fullData array // Remove non-users from the fullData array
const users = glDropdown.filteredFullData(); const users = glDropdown.filteredFullData();
const callback = glDropdown.parseData.bind(glDropdown); const callback = glDropdown.parseData.bind(glDropdown);
// Update the data model // Update the data model
this.processData(inputValue, users, callback); this.processData(inputValue, users, callback);
} }
if (this.multiSelect) { if (this.multiSelect) {
return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active')); return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
} }
if (selected && 'id' in selected && $(el).hasClass('is-active')) { if (selected && 'id' in selected && $(el).hasClass('is-active')) {
$dropdown.find('.dropdown-toggle-text').removeClass('is-default'); $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
if (selected.text) { if (selected.text) {
return selected.text; return selected.text;
} else {
return selected.name;
}
} else { } else {
return selected.name; $dropdown.find('.dropdown-toggle-text').addClass('is-default');
return defaultLabel;
}
},
defaultLabel: defaultLabel,
hidden: function(e) {
if ($dropdown.hasClass('js-multiselect')) {
emitSidebarEvent('sidebar.saveAssignees');
} }
} else {
$dropdown.find('.dropdown-toggle-text').addClass('is-default');
return defaultLabel;
}
},
defaultLabel: defaultLabel,
hidden: function(e) {
if ($dropdown.hasClass('js-multiselect')) {
emitSidebarEvent('sidebar.saveAssignees');
}
if (!$dropdown.data('alwaysShowSelectbox')) {
$selectbox.hide();
// Recalculate where .value is because vue might have changed it if (!$dropdown.data('alwaysShowSelectbox')) {
$block = $selectbox.closest('.block'); $selectbox.hide();
$value = $block.find('.value');
// display:block overrides the hide-collapse rule
$value.css('display', '');
}
},
multiSelect: $dropdown.hasClass('js-multiselect'),
inputMeta: $dropdown.data('inputMeta'),
clicked: function(options) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
if ($dropdown.hasClass('js-multiselect')) {
const isActive = $el.hasClass('is-active');
const previouslySelected = $dropdown.closest('.selectbox')
.find("input[name='" + ($dropdown.data('fieldName')) + "'][value!=0]");
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect();
if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') { // Recalculate where .value is because vue might have changed it
// Unassigned selected $block = $selectbox.closest('.block');
previouslySelected.each((index, element) => { $value = $block.find('.value');
const id = parseInt(element.value, 10); // display:block overrides the hide-collapse rule
element.remove(); $value.css('display', '');
}); }
emitSidebarEvent('sidebar.removeAllAssignees'); },
} else if (isActive) { multiSelect: $dropdown.hasClass('js-multiselect'),
// user selected inputMeta: $dropdown.data('inputMeta'),
emitSidebarEvent('sidebar.addAssignee', user); clicked: function(options) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
// Remove unassigned selection (if it was previously selected) if ($dropdown.hasClass('js-multiselect')) {
const unassignedSelected = $dropdown.closest('.selectbox') const isActive = $el.hasClass('is-active');
.find("input[name='" + ($dropdown.data('fieldName')) + "'][value=0]"); const previouslySelected = $dropdown
.closest('.selectbox')
.find("input[name='" + $dropdown.data('fieldName') + "'][value!=0]");
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect();
if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
// Unassigned selected
previouslySelected.each((index, element) => {
const id = parseInt(element.value, 10);
element.remove();
});
emitSidebarEvent('sidebar.removeAllAssignees');
} else if (isActive) {
// user selected
emitSidebarEvent('sidebar.addAssignee', user);
// Remove unassigned selection (if it was previously selected)
const unassignedSelected = $dropdown
.closest('.selectbox')
.find("input[name='" + $dropdown.data('fieldName') + "'][value=0]");
if (unassignedSelected) {
unassignedSelected.remove();
}
} else {
if (previouslySelected.length === 0) {
// Select unassigned because there is no more selected users
this.addInput($dropdown.data('fieldName'), 0, {});
}
if (unassignedSelected) { // User unselected
unassignedSelected.remove(); emitSidebarEvent('sidebar.removeAssignee', user);
}
} else {
if (previouslySelected.length === 0) {
// Select unassigned because there is no more selected users
this.addInput($dropdown.data('fieldName'), 0, {});
} }
// User unselected if (getSelected().find(u => u === gon.current_user_id)) {
emitSidebarEvent('sidebar.removeAssignee', user); $('.assign-to-me-link').hide();
} else {
$('.assign-to-me-link').show();
}
} }
if (getSelected().find(u => u === gon.current_user_id)) { var isIssueIndex, isMRIndex, page, selected;
$('.assign-to-me-link').hide(); page = $('body').attr('data-page');
} else { isIssueIndex = page === 'projects:issues:index';
$('.assign-to-me-link').show(); isMRIndex = page === page && page === 'projects:merge_requests:index';
if (
$dropdown.hasClass('js-filter-bulk-update') ||
$dropdown.hasClass('js-issuable-form-dropdown')
) {
e.preventDefault();
const isSelecting = user.id !== selectedId;
selectedId = isSelecting ? user.id : selectedIdDefault;
if (selectedId === gon.current_user_id) {
$('.assign-to-me-link').hide();
} else {
$('.assign-to-me-link').show();
}
return;
}
if ($el.closest('.add-issues-modal').length) {
ModalStore.store.filter[$dropdown.data('fieldName')] = user.id;
} else if (handleClick) {
e.preventDefault();
handleClick(user, isMarking);
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
return Issuable.filterResults($dropdown.closest('form'));
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
} else if (!$dropdown.hasClass('js-multiselect')) {
selected = $dropdown
.closest('.selectbox')
.find("input[name='" + $dropdown.data('fieldName') + "']")
.val();
return assignTo(selected);
} }
}
var isIssueIndex, isMRIndex, page, selected; // Automatically close dropdown after assignee is selected
page = $('body').attr('data-page'); // since CE has no multiple assignees
isIssueIndex = page === 'projects:issues:index'; // EE does not have a max-select
isMRIndex = (page === page && page === 'projects:merge_requests:index'); if (
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { $dropdown.data('maxSelect') &&
e.preventDefault(); getSelected().length === $dropdown.data('maxSelect')
) {
// Close the dropdown
$dropdown.dropdown('toggle');
}
},
id: function(user) {
return user.id;
},
opened: function(e) {
const $el = $(e.currentTarget);
const selected = getSelected();
if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) {
this.addInput($dropdown.data('fieldName'), 0, {});
}
$el.find('.is-active').removeClass('is-active');
const isSelecting = (user.id !== selectedId); function highlightSelected(id) {
selectedId = isSelecting ? user.id : selectedIdDefault; $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
}
if (selectedId === gon.current_user_id) { if (selected.length > 0) {
$('.assign-to-me-link').hide(); getSelected().forEach(selectedId => highlightSelected(selectedId));
} else if ($dropdown.hasClass('js-issue-board-sidebar')) {
highlightSelected(0);
} else { } else {
$('.assign-to-me-link').show(); highlightSelected(selectedId);
} }
return; },
} updateLabel: $dropdown.data('dropdownTitle'),
if ($el.closest('.add-issues-modal').length) { renderRow: function(user) {
ModalStore.store.filter[$dropdown.data('fieldName')] = user.id; var avatar, img, listClosingTags, listWithName, listWithUserName, username;
} else if (handleClick) { username = user.username ? '@' + user.username : '';
e.preventDefault(); avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
handleClick(user, isMarking);
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
return Issuable.filterResults($dropdown.closest('form'));
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
} else if (!$dropdown.hasClass('js-multiselect')) {
selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('fieldName')) + "']").val();
return assignTo(selected);
}
// Automatically close dropdown after assignee is selected
// since CE has no multiple assignees
// EE does not have a max-select
if ($dropdown.data('maxSelect') &&
getSelected().length === $dropdown.data('maxSelect')) {
// Close the dropdown
$dropdown.dropdown('toggle');
}
},
id: function (user) {
return user.id;
},
opened: function(e) {
const $el = $(e.currentTarget);
const selected = getSelected();
if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) {
this.addInput($dropdown.data('fieldName'), 0, {});
}
$el.find('.is-active').removeClass('is-active');
function highlightSelected(id) {
$el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
}
if (selected.length > 0) { let selected = false;
getSelected().forEach(selectedId => highlightSelected(selectedId));
} else if ($dropdown.hasClass('js-issue-board-sidebar')) {
highlightSelected(0);
} else {
highlightSelected(selectedId);
}
},
updateLabel: $dropdown.data('dropdownTitle'),
renderRow: function(user) {
var avatar, img, listClosingTags, listWithName, listWithUserName, username;
username = user.username ? "@" + user.username : "";
avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
let selected = false; if (this.multiSelect) {
selected = getSelected().find(u => user.id === u);
if (this.multiSelect) { const { fieldName } = this;
selected = getSelected().find(u => user.id === u); const field = $dropdown
.closest('.selectbox')
.find("input[name='" + fieldName + "'][value='" + user.id + "']");
const { fieldName } = this; if (field.length) {
const field = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "'][value='" + user.id + "']"); selected = true;
}
if (field.length) { } else {
selected = true; selected = user.id === selectedId;
} }
} else {
selected = user.id === selectedId;
}
img = ""; img = '';
if (user.beforeDivider != null) { if (user.beforeDivider != null) {
`<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(user.name)}</a></li>`; `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(
} else { user.name,
img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />"; )}</a></li>`;
} } else {
img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />";
}
return ` return `
<li data-user-id=${user.id}> <li data-user-id=${user.id}>
<a href='#' class='dropdown-menu-user-link ${selected === true ? 'is-active' : ''}'> <a href='#' class='dropdown-menu-user-link ${selected === true ? 'is-active' : ''}'>
${img} ${img}
...@@ -528,114 +574,117 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -528,114 +574,117 @@ function UsersSelect(currentUser, els, options = {}) {
</a> </a>
</li> </li>
`; `;
} },
}); });
}; };
})(this)); })(this),
$('.ajax-users-select').each((function(_this) { );
return function(i, select) { $('.ajax-users-select').each(
var firstUser, showAnyUser, showEmailUser, showNullUser; (function(_this) {
var options = {}; return function(i, select) {
options.skipLdap = $(select).hasClass('skip_ldap'); var firstUser, showAnyUser, showEmailUser, showNullUser;
options.projectId = $(select).data('projectId'); var options = {};
options.groupId = $(select).data('groupId'); options.skipLdap = $(select).hasClass('skip_ldap');
options.showCurrentUser = $(select).data('currentUser'); options.projectId = $(select).data('projectId');
options.authorId = $(select).data('authorId'); options.groupId = $(select).data('groupId');
options.skipUsers = $(select).data('skipUsers'); options.showCurrentUser = $(select).data('currentUser');
showNullUser = $(select).data('nullUser'); options.authorId = $(select).data('authorId');
showAnyUser = $(select).data('anyUser'); options.skipUsers = $(select).data('skipUsers');
showEmailUser = $(select).data('emailUser'); showNullUser = $(select).data('nullUser');
firstUser = $(select).data('firstUser'); showAnyUser = $(select).data('anyUser');
return $(select).select2({ showEmailUser = $(select).data('emailUser');
placeholder: "Search for a user", firstUser = $(select).data('firstUser');
multiple: $(select).hasClass('multiselect'), return $(select).select2({
minimumInputLength: 0, placeholder: 'Search for a user',
query: function(query) { multiple: $(select).hasClass('multiselect'),
return _this.users(query.term, options, function(users) { minimumInputLength: 0,
var anyUser, data, emailUser, index, len, name, nullUser, obj, ref; query: function(query) {
data = { return _this.users(query.term, options, function(users) {
results: users var anyUser, data, emailUser, index, len, name, nullUser, obj, ref;
}; data = {
if (query.term.length === 0) { results: users,
if (firstUser) { };
// Move current user to the front of the list if (query.term.length === 0) {
ref = data.results; if (firstUser) {
// Move current user to the front of the list
for (index = 0, len = ref.length; index < len; index += 1) { ref = data.results;
obj = ref[index];
if (obj.username === firstUser) { for (index = 0, len = ref.length; index < len; index += 1) {
data.results.splice(index, 1); obj = ref[index];
data.results.unshift(obj); if (obj.username === firstUser) {
break; data.results.splice(index, 1);
data.results.unshift(obj);
break;
}
} }
} }
} if (showNullUser) {
if (showNullUser) { nullUser = {
nullUser = { name: 'Unassigned',
name: 'Unassigned', id: 0,
id: 0 };
}; data.results.unshift(nullUser);
data.results.unshift(nullUser);
}
if (showAnyUser) {
name = showAnyUser;
if (name === true) {
name = 'Any User';
} }
anyUser = { if (showAnyUser) {
name: name, name = showAnyUser;
id: null if (name === true) {
name = 'Any User';
}
anyUser = {
name: name,
id: null,
};
data.results.unshift(anyUser);
}
}
if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
var trimmed = query.term.trim();
emailUser = {
name: 'Invite "' + trimmed + '" by email',
username: trimmed,
id: trimmed,
invite: true,
}; };
data.results.unshift(anyUser); data.results.unshift(emailUser);
} }
} return query.callback(data);
if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) { });
var trimmed = query.term.trim(); },
emailUser = { initSelection: function() {
name: "Invite \"" + trimmed + "\" by email", var args;
username: trimmed, args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
id: trimmed, return _this.initSelection.apply(_this, args);
invite: true },
}; formatResult: function() {
data.results.unshift(emailUser); var args;
} args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return query.callback(data); return _this.formatResult.apply(_this, args);
}); },
}, formatSelection: function() {
initSelection: function() { var args;
var args; args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; return _this.formatSelection.apply(_this, args);
return _this.initSelection.apply(_this, args); },
}, dropdownCssClass: 'ajax-users-dropdown',
formatResult: function() { // we do not want to escape markup since we are displaying html in results
var args; escapeMarkup: function(m) {
args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; return m;
return _this.formatResult.apply(_this, args); },
}, });
formatSelection: function() { };
var args; })(this),
args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; );
return _this.formatSelection.apply(_this, args);
},
dropdownCssClass: "ajax-users-dropdown",
// we do not want to escape markup since we are displaying html in results
escapeMarkup: function(m) {
return m;
}
});
};
})(this));
} }
UsersSelect.prototype.initSelection = function(element, callback) { UsersSelect.prototype.initSelection = function(element, callback) {
var id, nullUser; var id, nullUser;
id = $(element).val(); id = $(element).val();
if (id === "0") { if (id === '0') {
nullUser = { nullUser = {
name: 'Unassigned' name: 'Unassigned',
}; };
return callback(nullUser); return callback(nullUser);
} else if (id !== "") { } else if (id !== '') {
return this.user(id, callback); return this.user(id, callback);
} }
}; };
...@@ -647,7 +696,17 @@ UsersSelect.prototype.formatResult = function(user) { ...@@ -647,7 +696,17 @@ UsersSelect.prototype.formatResult = function(user) {
} else { } else {
avatar = gon.default_avatar_url; avatar = gon.default_avatar_url;
} }
return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar avatar-inline s32' src='" + avatar + "'></div> <div class='user-name dropdown-menu-user-full-name'>" + _.escape(user.name) + "</div> <div class='user-username dropdown-menu-user-username'>" + (!user.invite ? "@" + _.escape(user.username) : "") + "</div> </div>"; return (
"<div class='user-result " +
(!user.username ? 'no-username' : void 0) +
"'> <div class='user-image'><img class='avatar avatar-inline s32' src='" +
avatar +
"'></div> <div class='user-name dropdown-menu-user-full-name'>" +
_.escape(user.name) +
"</div> <div class='user-username dropdown-menu-user-username'>" +
(!user.invite ? '@' + _.escape(user.username) : '') +
'</div> </div>'
);
}; };
UsersSelect.prototype.formatSelection = function(user) { UsersSelect.prototype.formatSelection = function(user) {
...@@ -662,10 +721,9 @@ UsersSelect.prototype.user = function(user_id, callback) { ...@@ -662,10 +721,9 @@ UsersSelect.prototype.user = function(user_id, callback) {
var url; var url;
url = this.buildUrl(this.userPath); url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id); url = url.replace(':id', user_id);
return axios.get(url) return axios.get(url).then(({ data }) => {
.then(({ data }) => { callback(data);
callback(data); });
});
}; };
// Return users list. Filtered by query // Return users list. Filtered by query
...@@ -682,12 +740,11 @@ UsersSelect.prototype.users = function(query, options, callback) { ...@@ -682,12 +740,11 @@ UsersSelect.prototype.users = function(query, options, callback) {
todo_state_filter: options.todoStateFilter || null, todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null, current_user: options.showCurrentUser || null,
author_id: options.authorId || null, author_id: options.authorId || null,
skip_users: options.skipUsers || null skip_users: options.skipUsers || null,
}; };
return axios.get(url, { params }) return axios.get(url, { params }).then(({ data }) => {
.then(({ data }) => { callback(data);
callback(data); });
});
}; };
UsersSelect.prototype.buildUrl = function(url) { UsersSelect.prototype.buildUrl = function(url) {
......
...@@ -47,16 +47,26 @@ export default class ZenMode { ...@@ -47,16 +47,26 @@ export default class ZenMode {
e.preventDefault(); e.preventDefault();
return $(e.currentTarget).trigger('zen_mode:leave'); return $(e.currentTarget).trigger('zen_mode:leave');
}); });
$(document).on('zen_mode:enter', (function(_this) { $(document).on(
return function(e) { 'zen_mode:enter',
return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop')); (function(_this) {
}; return function(e) {
})(this)); return _this.enter(
$(document).on('zen_mode:leave', (function(_this) { $(e.target)
return function(e) { .closest('.md-area')
return _this.exit(); .find('.zen-backdrop'),
}; );
})(this)); };
})(this),
);
$(document).on(
'zen_mode:leave',
(function(_this) {
return function(e) {
return _this.exit();
};
})(this),
);
$(document).on('keydown', function(e) { $(document).on('keydown', function(e) {
// Esc // Esc
if (e.keyCode === 27) { if (e.keyCode === 27) {
...@@ -93,7 +103,7 @@ export default class ZenMode { ...@@ -93,7 +103,7 @@ export default class ZenMode {
scrollTo(zen_area) { scrollTo(zen_area) {
return $.scrollTo(zen_area, 0, { return $.scrollTo(zen_area, 0, {
offset: -150 offset: -150,
}); });
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment