Commit 29e1a63d authored by Phil Hughes's avatar Phil Hughes

Export JS classes as modules

#38869
parent c96e2edc
/* eslint-disable no-param-reassign, class-methods-use-this */ /* eslint-disable no-param-reassign, class-methods-use-this */
/* global Pager */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Pager from './pager';
import { localTimeAgo } from './lib/utils/datetime_utility'; import { localTimeAgo } from './lib/utils/datetime_utility';
export default class Activities { export default class Activities {
......
/* eslint-disable func-names, wrap-iife, consistent-return, /* eslint-disable func-names, wrap-iife, consistent-return,
no-return-assign, no-param-reassign, one-var-declaration-per-line, no-unused-vars, no-return-assign, no-param-reassign, one-var-declaration-per-line, no-unused-vars,
prefer-template, object-shorthand, prefer-arrow-callback */ prefer-template, object-shorthand, prefer-arrow-callback */
/* global Pager */
import { pluralize } from './lib/utils/text_utility'; import { pluralize } from './lib/utils/text_utility';
import { localTimeAgo } from './lib/utils/datetime_utility'; import { localTimeAgo } from './lib/utils/datetime_utility';
import Pager from './pager';
export default (function () { export default (function () {
const CommitsList = {}; const CommitsList = {};
......
...@@ -7,8 +7,8 @@ import IssuableForm from './issuable_form'; ...@@ -7,8 +7,8 @@ import IssuableForm from './issuable_form';
import LabelsSelect from './labels_select'; import LabelsSelect from './labels_select';
/* global MilestoneSelect */ /* global MilestoneSelect */
import NewBranchForm from './new_branch_form'; import NewBranchForm from './new_branch_form';
/* global NotificationsForm */ import NotificationsForm from './notifications_form';
/* global NotificationsDropdown */ import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar'; import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription'; import GroupLabelSubscription from './group_label_subscription';
/* global LineHighlighter */ /* global LineHighlighter */
...@@ -414,7 +414,7 @@ import Activities from './activities'; ...@@ -414,7 +414,7 @@ import Activities from './activities';
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup'); const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new NotificationsForm(); new NotificationsForm();
new NotificationsDropdown(); notificationsDropdown();
new ProjectsList(); new ProjectsList();
if (newGroupChildWrapper) { if (newGroupChildWrapper) {
...@@ -617,7 +617,7 @@ import Activities from './activities'; ...@@ -617,7 +617,7 @@ import Activities from './activities';
break; break;
case 'profiles': case 'profiles':
new NotificationsForm(); new NotificationsForm();
new NotificationsDropdown(); notificationsDropdown();
break; break;
case 'projects': case 'projects':
new Project(); new Project();
...@@ -640,7 +640,7 @@ import Activities from './activities'; ...@@ -640,7 +640,7 @@ import Activities from './activities';
case 'show': case 'show':
new Star(); new Star();
new ProjectNew(); new ProjectNew();
new NotificationsDropdown(); notificationsDropdown();
break; break;
case 'wikis': case 'wikis':
new Wikis(); new Wikis();
......
...@@ -34,16 +34,11 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility'; ...@@ -34,16 +34,11 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility';
import './behaviors/'; import './behaviors/';
// everything else // everything else
import './activities';
import './admin';
import loadAwardsHandler from './awards_handler'; import loadAwardsHandler from './awards_handler';
import bp from './breakpoints'; import bp from './breakpoints';
import './confirm_danger_modal'; import './confirm_danger_modal';
import Flash, { removeFlashClickListener } from './flash'; import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown'; import './gl_dropdown';
import './gl_field_error';
import './gl_field_errors';
import './gl_form';
import initTodoToggle from './header'; import initTodoToggle from './header';
import initImporterStatus from './importer_status'; import initImporterStatus from './importer_status';
import './layout_nav'; import './layout_nav';
...@@ -54,11 +49,7 @@ import './merge_request'; ...@@ -54,11 +49,7 @@ import './merge_request';
import './merge_request_tabs'; import './merge_request_tabs';
import './milestone_select'; import './milestone_select';
import './notes'; import './notes';
import './notifications_dropdown';
import './notifications_form';
import './pager';
import './preview_markdown'; import './preview_markdown';
import './project_import';
import './projects_dropdown'; import './projects_dropdown';
import './render_gfm'; import './render_gfm';
import './right_sidebar'; import './right_sidebar';
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import 'vendor/jquery.waitforimages'; import 'vendor/jquery.waitforimages';
import TaskList from './task_list'; import TaskList from './task_list';
import './merge_request_tabs'; import MergeRequestTabs from './merge_request_tabs';
import IssuablesHelper from './helpers/issuables_helper'; import IssuablesHelper from './helpers/issuables_helper';
import { addDelimiter } from './lib/utils/text_utility'; import { addDelimiter } from './lib/utils/text_utility';
...@@ -51,7 +51,7 @@ import { addDelimiter } from './lib/utils/text_utility'; ...@@ -51,7 +51,7 @@ import { addDelimiter } from './lib/utils/text_utility';
if (window.mrTabs) { if (window.mrTabs) {
window.mrTabs.unbindEvents(); window.mrTabs.unbindEvents();
} }
window.mrTabs = new gl.MergeRequestTabs(this.opts); window.mrTabs = new MergeRequestTabs(this.opts);
}; };
MergeRequest.prototype.showAllCommits = function() { MergeRequest.prototype.showAllCommits = function() {
......
...@@ -63,387 +63,382 @@ import syntaxHighlight from './syntax_highlight'; ...@@ -63,387 +63,382 @@ import syntaxHighlight from './syntax_highlight';
// //
/* eslint-enable max-len */ /* eslint-enable max-len */
(() => { // Store the `location` object, allowing for easier stubbing in tests
// Store the `location` object, allowing for easier stubbing in tests let location = window.location;
let location = window.location;
class MergeRequestTabs {
constructor({ action, setUrl, stubLocation } = {}) {
const mergeRequestTabs = document.querySelector('.js-tabs-affix');
const navbar = document.querySelector('.navbar-gitlab');
const paddingTop = 16;
this.diffsLoaded = false;
this.pipelinesLoaded = false;
this.commitsLoaded = false;
this.fixedLayoutPref = null;
this.setUrl = setUrl !== undefined ? setUrl : true;
this.setCurrentAction = this.setCurrentAction.bind(this);
this.tabShown = this.tabShown.bind(this);
this.showTab = this.showTab.bind(this);
this.stickyTop = navbar ? navbar.offsetHeight - paddingTop : 0;
if (mergeRequestTabs) {
this.stickyTop += mergeRequestTabs.offsetHeight;
}
if (stubLocation) { export default class MergeRequestTabs {
location = stubLocation;
}
this.bindEvents(); constructor({ action, setUrl, stubLocation } = {}) {
this.activateTab(action); const mergeRequestTabs = document.querySelector('.js-tabs-affix');
this.initAffix(); const navbar = document.querySelector('.navbar-gitlab');
} const paddingTop = 16;
bindEvents() { this.diffsLoaded = false;
$(document) this.pipelinesLoaded = false;
.on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) this.commitsLoaded = false;
.on('click', '.js-show-tab', this.showTab); this.fixedLayoutPref = null;
$('.merge-request-tabs a[data-toggle="tab"]') this.setUrl = setUrl !== undefined ? setUrl : true;
.on('click', this.clickTab); this.setCurrentAction = this.setCurrentAction.bind(this);
} this.tabShown = this.tabShown.bind(this);
this.showTab = this.showTab.bind(this);
this.stickyTop = navbar ? navbar.offsetHeight - paddingTop : 0;
// Used in tests if (mergeRequestTabs) {
unbindEvents() { this.stickyTop += mergeRequestTabs.offsetHeight;
$(document) }
.off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
.off('click', '.js-show-tab', this.showTab);
$('.merge-request-tabs a[data-toggle="tab"]') if (stubLocation) {
.off('click', this.clickTab); location = stubLocation;
} }
destroyPipelinesView() { this.bindEvents();
if (this.commitPipelinesTable) { this.activateTab(action);
this.commitPipelinesTable.$destroy(); this.initAffix();
this.commitPipelinesTable = null; }
document.querySelector('#commit-pipeline-table-view').innerHTML = ''; bindEvents() {
} $(document)
} .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
.on('click', '.js-show-tab', this.showTab);
showTab(e) { $('.merge-request-tabs a[data-toggle="tab"]')
e.preventDefault(); .on('click', this.clickTab);
this.activateTab($(e.target).data('action')); }
}
clickTab(e) { // Used in tests
if (e.currentTarget && isMetaClick(e)) { unbindEvents() {
const targetLink = e.currentTarget.getAttribute('href'); $(document)
e.stopImmediatePropagation(); .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
e.preventDefault(); .off('click', '.js-show-tab', this.showTab);
window.open(targetLink, '_blank');
} $('.merge-request-tabs a[data-toggle="tab"]')
.off('click', this.clickTab);
}
destroyPipelinesView() {
if (this.commitPipelinesTable) {
this.commitPipelinesTable.$destroy();
this.commitPipelinesTable = null;
document.querySelector('#commit-pipeline-table-view').innerHTML = '';
} }
}
tabShown(e) { showTab(e) {
const $target = $(e.target); e.preventDefault();
const action = $target.data('action'); this.activateTab($(e.target).data('action'));
}
if (action === 'commits') { clickTab(e) {
this.loadCommits($target.attr('href')); if (e.currentTarget && isMetaClick(e)) {
this.expandView(); const targetLink = e.currentTarget.getAttribute('href');
this.resetViewContainer(); e.stopImmediatePropagation();
this.destroyPipelinesView(); e.preventDefault();
} else if (this.isDiffAction(action)) { window.open(targetLink, '_blank');
this.loadDiff($target.attr('href')); }
if (bp.getBreakpointSize() !== 'lg') { }
this.shrinkView();
}
if (this.diffViewType() === 'parallel') {
this.expandViewContainer();
}
this.destroyPipelinesView();
} else if (action === 'pipelines') {
this.resetViewContainer();
this.mountPipelinesView();
} else {
if (bp.getBreakpointSize() !== 'xs') {
this.expandView();
}
this.resetViewContainer();
this.destroyPipelinesView();
initDiscussionTab(); tabShown(e) {
const $target = $(e.target);
const action = $target.data('action');
if (action === 'commits') {
this.loadCommits($target.attr('href'));
this.expandView();
this.resetViewContainer();
this.destroyPipelinesView();
} else if (this.isDiffAction(action)) {
this.loadDiff($target.attr('href'));
if (bp.getBreakpointSize() !== 'lg') {
this.shrinkView();
} }
if (this.setUrl) { if (this.diffViewType() === 'parallel') {
this.setCurrentAction(action); this.expandViewContainer();
} }
this.destroyPipelinesView();
} else if (action === 'pipelines') {
this.resetViewContainer();
this.mountPipelinesView();
} else {
if (bp.getBreakpointSize() !== 'xs') {
this.expandView();
}
this.resetViewContainer();
this.destroyPipelinesView();
initDiscussionTab();
}
if (this.setUrl) {
this.setCurrentAction(action);
} }
}
scrollToElement(container) { scrollToElement(container) {
if (location.hash) { if (location.hash) {
const offset = 0 - ( const offset = 0 - (
$('.navbar-gitlab').outerHeight() + $('.navbar-gitlab').outerHeight() +
$('.js-tabs-affix').outerHeight() $('.js-tabs-affix').outerHeight()
); );
const $el = $(`${container} ${location.hash}:not(.match)`); const $el = $(`${container} ${location.hash}:not(.match)`);
if ($el.length) { if ($el.length) {
$.scrollTo($el[0], { offset }); $.scrollTo($el[0], { offset });
}
} }
} }
}
// Activate a tab based on the current action
activateTab(action) {
// important note: the .tab('show') method triggers 'shown.bs.tab' event itself
$(`.merge-request-tabs a[data-action='${action}']`).tab('show');
}
// Activate a tab based on the current action // Replaces the current Merge Request-specific action in the URL with a new one
activateTab(action) { //
// important note: the .tab('show') method triggers 'shown.bs.tab' event itself // If the action is "notes", the URL is reset to the standard
$(`.merge-request-tabs a[data-action='${action}']`).tab('show'); // `MergeRequests#show` route.
//
// Examples:
//
// location.pathname # => "/namespace/project/merge_requests/1"
// setCurrentAction('diffs')
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
//
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
// setCurrentAction('show')
// location.pathname # => "/namespace/project/merge_requests/1"
//
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
// setCurrentAction('commits')
// location.pathname # => "/namespace/project/merge_requests/1/commits"
//
// Returns the new URL String
setCurrentAction(action) {
this.currentAction = action;
// Remove a trailing '/commits' '/diffs' '/pipelines'
let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, '');
// Append the new action if we're on a tab other than 'notes'
if (this.currentAction !== 'show' && this.currentAction !== 'new') {
newState += `/${this.currentAction}`;
} }
// Replaces the current Merge Request-specific action in the URL with a new one // Ensure parameters and hash come along for the ride
// newState += location.search + location.hash;
// If the action is "notes", the URL is reset to the standard
// `MergeRequests#show` route.
//
// Examples:
//
// location.pathname # => "/namespace/project/merge_requests/1"
// setCurrentAction('diffs')
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
//
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
// setCurrentAction('show')
// location.pathname # => "/namespace/project/merge_requests/1"
//
// location.pathname # => "/namespace/project/merge_requests/1/diffs"
// setCurrentAction('commits')
// location.pathname # => "/namespace/project/merge_requests/1/commits"
//
// Returns the new URL String
setCurrentAction(action) {
this.currentAction = action;
// Remove a trailing '/commits' '/diffs' '/pipelines' // TODO: Consider refactoring in light of turbolinks removal.
let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, '');
// Append the new action if we're on a tab other than 'notes' // Replace the current history state with the new one without breaking
if (this.currentAction !== 'show' && this.currentAction !== 'new') { // Turbolinks' history.
newState += `/${this.currentAction}`; //
} // See https://github.com/rails/turbolinks/issues/363
window.history.replaceState({
url: newState,
}, document.title, newState);
// Ensure parameters and hash come along for the ride return newState;
newState += location.search + location.hash; }
// TODO: Consider refactoring in light of turbolinks removal. loadCommits(source) {
if (this.commitsLoaded) {
return;
}
this.ajaxGet({
url: `${source}.json`,
success: (data) => {
document.querySelector('div#commits').innerHTML = data.html;
localTimeAgo($('.js-timeago', 'div#commits'));
this.commitsLoaded = true;
this.scrollToElement('#commits');
},
});
}
// Replace the current history state with the new one without breaking mountPipelinesView() {
// Turbolinks' history. const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view');
// const CommitPipelinesTable = gl.CommitPipelinesTable;
// See https://github.com/rails/turbolinks/issues/363 this.commitPipelinesTable = new CommitPipelinesTable({
window.history.replaceState({ propsData: {
url: newState, endpoint: pipelineTableViewEl.dataset.endpoint,
}, document.title, newState); helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
// $mount(el) replaces the el with the new rendered component. We need it in order to mount
// it everytime this tab is clicked - https://vuejs.org/v2/api/#vm-mount
pipelineTableViewEl.appendChild(this.commitPipelinesTable.$el);
}
return newState; loadDiff(source) {
if (this.diffsLoaded) {
document.dispatchEvent(new CustomEvent('scroll'));
return;
} }
loadCommits(source) { // We extract pathname for the current Changes tab anchor href
if (this.commitsLoaded) { // some pages like MergeRequestsController#new has query parameters on that anchor
return; const urlPathname = parseUrlPathname(source);
}
this.ajaxGet({
url: `${source}.json`,
success: (data) => {
document.querySelector('div#commits').innerHTML = data.html;
localTimeAgo($('.js-timeago', 'div#commits'));
this.commitsLoaded = true;
this.scrollToElement('#commits');
},
});
}
mountPipelinesView() { this.ajaxGet({
const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); url: `${urlPathname}.json${location.search}`,
const CommitPipelinesTable = gl.CommitPipelinesTable; success: (data) => {
this.commitPipelinesTable = new CommitPipelinesTable({ const $container = $('#diffs');
propsData: { $container.html(data.html);
endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
// $mount(el) replaces the el with the new rendered component. We need it in order to mount initChangesDropdown(this.stickyTop);
// it everytime this tab is clicked - https://vuejs.org/v2/api/#vm-mount
pipelineTableViewEl.appendChild(this.commitPipelinesTable.$el);
}
loadDiff(source) { if (typeof gl.diffNotesCompileComponents !== 'undefined') {
if (this.diffsLoaded) { gl.diffNotesCompileComponents();
document.dispatchEvent(new CustomEvent('scroll')); }
return;
} localTimeAgo($('.js-timeago', 'div#diffs'));
syntaxHighlight($('#diffs .js-syntax-highlight'));
// We extract pathname for the current Changes tab anchor href if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) {
// some pages like MergeRequestsController#new has query parameters on that anchor this.expandViewContainer();
const urlPathname = parseUrlPathname(source); }
this.diffsLoaded = true;
this.ajaxGet({
url: `${urlPathname}.json${location.search}`, new Diff();
success: (data) => { this.scrollToElement('#diffs');
const $container = $('#diffs');
$container.html(data.html); $('.diff-file').each((i, el) => {
new BlobForkSuggestion({
initChangesDropdown(this.stickyTop); openButtons: $(el).find('.js-edit-blob-link-fork-toggler'),
forkButtons: $(el).find('.js-fork-suggestion-button'),
if (typeof gl.diffNotesCompileComponents !== 'undefined') { cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'),
gl.diffNotesCompileComponents(); suggestionSections: $(el).find('.js-file-fork-suggestion-section'),
} actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'),
})
localTimeAgo($('.js-timeago', 'div#diffs')); .init();
syntaxHighlight($('#diffs .js-syntax-highlight')); });
if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) { // Scroll any linked note into view
this.expandViewContainer(); // Similar to `toggler_behavior` in the discussion tab
} const hash = getLocationHash();
this.diffsLoaded = true; const anchor = hash && $container.find(`.note[id="${hash}"]`);
if (anchor && anchor.length > 0) {
new Diff(); const notesContent = anchor.closest('.notes_content');
this.scrollToElement('#diffs'); const lineType = notesContent.hasClass('new') ? 'new' : 'old';
notes.toggleDiffNote({
$('.diff-file').each((i, el) => { target: anchor,
new BlobForkSuggestion({ lineType,
openButtons: $(el).find('.js-edit-blob-link-fork-toggler'), forceShow: true,
forkButtons: $(el).find('.js-fork-suggestion-button'),
cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'),
suggestionSections: $(el).find('.js-file-fork-suggestion-section'),
actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'),
})
.init();
}); });
anchor[0].scrollIntoView();
handleLocationHash();
// We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target');
}
},
});
}
// Scroll any linked note into view // Show or hide the loading spinner
// Similar to `toggler_behavior` in the discussion tab //
const hash = getLocationHash(); // status - Boolean, true to show, false to hide
const anchor = hash && $container.find(`.note[id="${hash}"]`); toggleLoading(status) {
if (anchor && anchor.length > 0) { $('.mr-loading-status .loading').toggle(status);
const notesContent = anchor.closest('.notes_content'); }
const lineType = notesContent.hasClass('new') ? 'new' : 'old';
notes.toggleDiffNote({
target: anchor,
lineType,
forceShow: true,
});
anchor[0].scrollIntoView();
handleLocationHash();
// We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target');
}
},
});
}
// Show or hide the loading spinner ajaxGet(options) {
// const defaults = {
// status - Boolean, true to show, false to hide beforeSend: () => this.toggleLoading(true),
toggleLoading(status) { error: () => new Flash('An error occurred while fetching this tab.', 'alert'),
$('.mr-loading-status .loading').toggle(status); complete: () => this.toggleLoading(false),
} dataType: 'json',
type: 'GET',
};
$.ajax($.extend({}, defaults, options));
}
ajaxGet(options) { diffViewType() {
const defaults = { return $('.inline-parallel-buttons a.active').data('view-type');
beforeSend: () => this.toggleLoading(true), }
error: () => new Flash('An error occurred while fetching this tab.', 'alert'),
complete: () => this.toggleLoading(false),
dataType: 'json',
type: 'GET',
};
$.ajax($.extend({}, defaults, options));
}
diffViewType() { isDiffAction(action) {
return $('.inline-parallel-buttons a.active').data('view-type'); return action === 'diffs' || action === 'new/diffs';
} }
isDiffAction(action) { expandViewContainer() {
return action === 'diffs' || action === 'new/diffs'; const $wrapper = $('.content-wrapper .container-fluid').not('.breadcrumbs');
if (this.fixedLayoutPref === null) {
this.fixedLayoutPref = $wrapper.hasClass('container-limited');
} }
$wrapper.removeClass('container-limited');
}
expandViewContainer() { resetViewContainer() {
const $wrapper = $('.content-wrapper .container-fluid').not('.breadcrumbs'); if (this.fixedLayoutPref !== null) {
if (this.fixedLayoutPref === null) { $('.content-wrapper .container-fluid')
this.fixedLayoutPref = $wrapper.hasClass('container-limited'); .toggleClass('container-limited', this.fixedLayoutPref);
}
$wrapper.removeClass('container-limited');
} }
}
resetViewContainer() { shrinkView() {
if (this.fixedLayoutPref !== null) { const $gutterIcon = $('.js-sidebar-toggle i:visible');
$('.content-wrapper .container-fluid')
.toggleClass('container-limited', this.fixedLayoutPref);
}
}
shrinkView() { // Wait until listeners are set
const $gutterIcon = $('.js-sidebar-toggle i:visible'); setTimeout(() => {
// Only when sidebar is expanded
if ($gutterIcon.is('.fa-angle-double-right')) {
$gutterIcon.closest('a').trigger('click', [true]);
}
}, 0);
}
// Wait until listeners are set // Expand the issuable sidebar unless the user explicitly collapsed it
setTimeout(() => { expandView() {
// Only when sidebar is expanded if (Cookies.get('collapsed_gutter') === 'true') {
if ($gutterIcon.is('.fa-angle-double-right')) { return;
$gutterIcon.closest('a').trigger('click', [true]);
}
}, 0);
} }
const $gutterIcon = $('.js-sidebar-toggle i:visible');
// Expand the issuable sidebar unless the user explicitly collapsed it // Wait until listeners are set
expandView() { setTimeout(() => {
if (Cookies.get('collapsed_gutter') === 'true') { // Only when sidebar is collapsed
return; if ($gutterIcon.is('.fa-angle-double-left')) {
$gutterIcon.closest('a').trigger('click', [true]);
} }
const $gutterIcon = $('.js-sidebar-toggle i:visible'); }, 0);
}
// Wait until listeners are set initAffix() {
setTimeout(() => { const $tabs = $('.js-tabs-affix');
// Only when sidebar is collapsed const $fixedNav = $('.navbar-gitlab');
if ($gutterIcon.is('.fa-angle-double-left')) {
$gutterIcon.closest('a').trigger('click', [true]); // Screen space on small screens is usually very sparse
} // So we dont affix the tabs on these
}, 0); if (bp.getBreakpointSize() === 'xs' || !$tabs.length) return;
}
/**
If the browser does not support position sticky, it returns the position as static.
If the browser does support sticky, then we allow the browser to handle it, if not
then we default back to Bootstraps affix
**/
if ($tabs.css('position') !== 'static') return;
const $diffTabs = $('#diff-notes-app');
$tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({
offset: {
top: () => (
$diffTabs.offset().top - $tabs.height() - $fixedNav.height()
),
},
})
.on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() }))
.on('affix-top.bs.affix', () => $diffTabs.css({ marginTop: '' }));
initAffix() { // Fix bug when reloading the page already scrolling
const $tabs = $('.js-tabs-affix'); if ($tabs.hasClass('affix')) {
const $fixedNav = $('.navbar-gitlab'); $tabs.trigger('affix.bs.affix');
// Screen space on small screens is usually very sparse
// So we dont affix the tabs on these
if (bp.getBreakpointSize() === 'xs' || !$tabs.length) return;
/**
If the browser does not support position sticky, it returns the position as static.
If the browser does support sticky, then we allow the browser to handle it, if not
then we default back to Bootstraps affix
**/
if ($tabs.css('position') !== 'static') return;
const $diffTabs = $('#diff-notes-app');
$tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({
offset: {
top: () => (
$diffTabs.offset().top - $tabs.height() - $fixedNav.height()
),
},
})
.on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() }))
.on('affix-top.bs.affix', () => $diffTabs.css({ marginTop: '' }));
// Fix bug when reloading the page already scrolling
if ($tabs.hasClass('affix')) {
$tabs.trigger('affix.bs.affix');
}
} }
} }
}
window.gl = window.gl || {};
window.gl.MergeRequestTabs = MergeRequestTabs;
})();
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, consistent-return, prefer-arrow-callback, no-else-return, max-len */
import Flash from './flash'; import Flash from './flash';
(function() { export default function notificationsDropdown() {
this.NotificationsDropdown = (function() { $(document).on('click', '.update-notification', function updateNotificationCallback(e) {
function NotificationsDropdown() { e.preventDefault();
$(document).off('click', '.update-notification').on('click', '.update-notification', function(e) { if ($(this).is('.is-active') && $(this).data('notification-level') === 'custom') {
var form, label, notificationLevel; return;
e.preventDefault();
if ($(this).is('.is-active') && $(this).data('notification-level') === 'custom') {
return;
}
notificationLevel = $(this).data('notification-level');
label = $(this).data('notification-title');
form = $(this).parents('.notification-form:first');
form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner');
form.find('#notification_setting_level').val(notificationLevel);
return form.submit();
});
$(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) {
if (data.saved) {
return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
} else {
return new Flash('Failed to save new settings', 'alert');
}
});
} }
return NotificationsDropdown; const notificationLevel = $(this).data('notification-level');
})(); const form = $(this).parents('.notification-form:first');
}).call(window);
form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner');
form.find('#notification_setting_level').val(notificationLevel);
form.submit();
});
$(document).on('ajax:success', '.notification-form', (e, data) => {
if (data.saved) {
$(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
} else {
Flash('Failed to save new settings', 'alert');
}
});
}
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, one-var-declaration-per-line, newline-per-chained-call, comma-dangle, consistent-return, prefer-arrow-callback, max-len */ export default class NotificationsForm {
(function() { constructor() {
this.NotificationsForm = (function() { this.toggleCheckbox = this.toggleCheckbox.bind(this);
function NotificationsForm() { this.initEventListeners();
this.toggleCheckbox = this.toggleCheckbox.bind(this); }
this.removeEventListeners();
this.initEventListeners();
}
NotificationsForm.prototype.removeEventListeners = function() { initEventListeners() {
return $(document).off('change', '.js-custom-notification-event'); $(document).on('change', '.js-custom-notification-event', this.toggleCheckbox);
}; }
NotificationsForm.prototype.initEventListeners = function() { toggleCheckbox(e) {
return $(document).on('change', '.js-custom-notification-event', this.toggleCheckbox); const $checkbox = $(e.currentTarget);
}; const $parent = $checkbox.closest('.checkbox');
NotificationsForm.prototype.toggleCheckbox = function(e) { this.saveEvent($checkbox, $parent);
var $checkbox, $parent; }
$checkbox = $(e.currentTarget);
$parent = $checkbox.closest('.checkbox');
return this.saveEvent($checkbox, $parent);
};
NotificationsForm.prototype.showCheckboxLoadingSpinner = function($parent) { // eslint-disable-next-line class-methods-use-this
return $parent.addClass('is-loading').find('.custom-notification-event-loading').removeClass('fa-check').addClass('fa-spin fa-spinner').removeClass('is-done'); showCheckboxLoadingSpinner($parent) {
}; $parent.addClass('is-loading')
.find('.custom-notification-event-loading')
.removeClass('fa-check')
.addClass('fa-spin fa-spinner')
.removeClass('is-done');
}
NotificationsForm.prototype.saveEvent = function($checkbox, $parent) { saveEvent($checkbox, $parent) {
var form; const form = $parent.parents('form:first');
form = $parent.parents('form:first');
return $.ajax({
url: form.attr('action'),
method: form.attr('method'),
dataType: 'json',
data: form.serialize(),
beforeSend: (function(_this) {
return function() {
return _this.showCheckboxLoadingSpinner($parent);
};
})(this)
}).done(function(data) {
$checkbox.enable();
if (data.saved) {
$parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
return setTimeout(function() {
return $parent.removeClass('is-loading').find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
}, 2000);
}
});
};
return NotificationsForm; return $.ajax({
})(); url: form.attr('action'),
}).call(window); method: form.attr('method'),
dataType: 'json',
data: form.serialize(),
beforeSend: () => {
this.showCheckboxLoadingSpinner($parent);
},
}).done((data) => {
$checkbox.enable();
if (data.saved) {
$parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
setTimeout(() => {
$parent.removeClass('is-loading')
.find('.custom-notification-event-loading')
.toggleClass('fa-spin fa-spinner fa-check is-done');
}, 2000);
}
});
}
}
import { getParameterByName } from '~/lib/utils/common_utils'; import { getParameterByName } from '~/lib/utils/common_utils';
import { removeParams } from './lib/utils/url_utility'; import { removeParams } from './lib/utils/url_utility';
(() => { const ENDLESS_SCROLL_BOTTOM_PX = 400;
const ENDLESS_SCROLL_BOTTOM_PX = 400; const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000;
const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000;
const Pager = { export default {
init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) { init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) {
this.url = $('.content_list').data('href') || removeParams(['limit', 'offset']); this.url = $('.content_list').data('href') || removeParams(['limit', 'offset']);
this.limit = limit; this.limit = limit;
this.offset = parseInt(getParameterByName('offset'), 10) || this.limit; this.offset = parseInt(getParameterByName('offset'), 10) || this.limit;
this.disable = disable; this.disable = disable;
this.prepareData = prepareData; this.prepareData = prepareData;
this.callback = callback; this.callback = callback;
this.loading = $('.loading').first(); this.loading = $('.loading').first();
if (preload) { if (preload) {
this.offset = 0; this.offset = 0;
this.getOld(); this.getOld();
} }
this.initLoadMore(); this.initLoadMore();
}, },
getOld() { getOld() {
this.loading.show(); this.loading.show();
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: this.url, url: this.url,
data: `limit=${this.limit}&offset=${this.offset}`, data: `limit=${this.limit}&offset=${this.offset}`,
dataType: 'json', dataType: 'json',
error: () => this.loading.hide(), error: () => this.loading.hide(),
success: (data) => { success: (data) => {
this.append(data.count, this.prepareData(data.html)); this.append(data.count, this.prepareData(data.html));
this.callback(); 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();
} }
}, },
}); });
}, },
append(count, html) { append(count, html) {
$('.content_list').append(html); $('.content_list').append(html);
if (count > 0) { if (count > 0) {
this.offset += count; this.offset += count;
} else { } else {
this.disable = true; this.disable = true;
} }
}, },
isScrollable() { isScrollable() {
const $w = $(window); const $w = $(window);
return $(document).height() > $w.height() + $w.scrollTop() + ENDLESS_SCROLL_BOTTOM_PX; return $(document).height() > $w.height() + $w.scrollTop() + ENDLESS_SCROLL_BOTTOM_PX;
}, },
initLoadMore() { initLoadMore() {
$(document).unbind('scroll'); $(document).unbind('scroll');
$(document).endlessScroll({ $(document).endlessScroll({
bottomPixels: ENDLESS_SCROLL_BOTTOM_PX, bottomPixels: ENDLESS_SCROLL_BOTTOM_PX,
fireDelay: ENDLESS_SCROLL_FIRE_DELAY_MS, fireDelay: ENDLESS_SCROLL_FIRE_DELAY_MS,
fireOnce: true, fireOnce: true,
ceaseFire: () => this.disable === true, ceaseFire: () => this.disable === true,
callback: () => { callback: () => {
if (!this.loading.is(':visible')) { if (!this.loading.is(':visible')) {
this.loading.show(); this.loading.show();
this.getOld(); this.getOld();
} }
}, },
}); });
}, },
}; };
window.Pager = Pager;
})();
/* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, no-shadow, max-len */ /* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, no-shadow, max-len */
import 'vendor/jquery.endless-scroll'; import 'vendor/jquery.endless-scroll';
import '~/pager';
import Activities from '~/activities'; import Activities from '~/activities';
(() => { (() => {
......
import 'vendor/jquery.endless-scroll'; import 'vendor/jquery.endless-scroll';
import '~/pager';
import CommitsList from '~/commits'; import CommitsList from '~/commits';
describe('Commits List', () => { describe('Commits List', () => {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* global Notes */ /* global Notes */
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import '~/merge_request_tabs'; import MergeRequestTabs from '~/merge_request_tabs';
import '~/commit/pipelines/pipelines_bundle'; import '~/commit/pipelines/pipelines_bundle';
import '~/breakpoints'; import '~/breakpoints';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
...@@ -32,7 +32,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -32,7 +32,7 @@ import 'vendor/jquery.scrollTo';
); );
beforeEach(function () { beforeEach(function () {
this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation }); this.class = new MergeRequestTabs({ stubLocation: stubLocation });
setLocation(); setLocation();
this.spies = { this.spies = {
......
/* global fixture */ /* global fixture */
import * as utils from '~/lib/utils/url_utility'; import * as utils from '~/lib/utils/url_utility';
import '~/pager'; import Pager from '~/pager';
describe('pager', () => { describe('pager', () => {
const Pager = window.Pager;
it('is defined on window', () => {
expect(window.Pager).toBeDefined();
});
describe('init', () => { describe('init', () => {
const originalHref = window.location.href; const originalHref = window.location.href;
......
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