Remove IIFEs around several javascript classes
This commit is contained in:
parent
11e03bf49c
commit
c06dad62e1
15 changed files with 821 additions and 843 deletions
|
@ -2,56 +2,54 @@
|
||||||
/* eslint no-new: "off" */
|
/* eslint no-new: "off" */
|
||||||
import AccessorUtilities from './lib/utils/accessor';
|
import AccessorUtilities from './lib/utils/accessor';
|
||||||
|
|
||||||
((global) => {
|
/**
|
||||||
/**
|
* Memorize the last selected tab after reloading a page.
|
||||||
* Memorize the last selected tab after reloading a page.
|
* Does that setting the current selected tab in the localStorage
|
||||||
* Does that setting the current selected tab in the localStorage
|
*/
|
||||||
*/
|
class ActiveTabMemoizer {
|
||||||
class ActiveTabMemoizer {
|
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
|
||||||
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
|
this.currentTabKey = currentTabKey;
|
||||||
this.currentTabKey = currentTabKey;
|
this.tabSelector = tabSelector;
|
||||||
this.tabSelector = tabSelector;
|
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
|
||||||
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
|
|
||||||
|
|
||||||
this.bootstrap();
|
this.bootstrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap() {
|
bootstrap() {
|
||||||
const tabs = document.querySelectorAll(this.tabSelector);
|
const tabs = document.querySelectorAll(this.tabSelector);
|
||||||
if (tabs.length > 0) {
|
if (tabs.length > 0) {
|
||||||
tabs[0].addEventListener('click', (e) => {
|
tabs[0].addEventListener('click', (e) => {
|
||||||
if (e.target && e.target.nodeName === 'A') {
|
if (e.target && e.target.nodeName === 'A') {
|
||||||
const anchorName = e.target.getAttribute('href');
|
const anchorName = e.target.getAttribute('href');
|
||||||
this.saveData(anchorName);
|
this.saveData(anchorName);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
showTab() {
|
|
||||||
const anchorName = this.readData();
|
|
||||||
if (anchorName) {
|
|
||||||
const tab = document.querySelector(`${this.tabSelector} a[href="${anchorName}"]`);
|
|
||||||
if (tab) {
|
|
||||||
tab.click();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
showTab() {
|
||||||
|
const anchorName = this.readData();
|
||||||
|
if (anchorName) {
|
||||||
|
const tab = document.querySelector(`${this.tabSelector} a[href="${anchorName}"]`);
|
||||||
|
if (tab) {
|
||||||
|
tab.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData(val) {
|
|
||||||
if (!this.isLocalStorageAvailable) return undefined;
|
|
||||||
|
|
||||||
return window.localStorage.setItem(this.currentTabKey, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
readData() {
|
|
||||||
if (!this.isLocalStorageAvailable) return null;
|
|
||||||
|
|
||||||
return window.localStorage.getItem(this.currentTabKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.ActiveTabMemoizer = ActiveTabMemoizer;
|
saveData(val) {
|
||||||
})(window);
|
if (!this.isLocalStorageAvailable) return undefined;
|
||||||
|
|
||||||
|
return window.localStorage.setItem(this.currentTabKey, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
readData() {
|
||||||
|
if (!this.isLocalStorageAvailable) return null;
|
||||||
|
|
||||||
|
return window.localStorage.getItem(this.currentTabKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ActiveTabMemoizer = ActiveTabMemoizer;
|
||||||
|
|
|
@ -2,99 +2,97 @@
|
||||||
|
|
||||||
import FilesCommentButton from './files_comment_button';
|
import FilesCommentButton from './files_comment_button';
|
||||||
|
|
||||||
(function() {
|
window.SingleFileDiff = (function() {
|
||||||
window.SingleFileDiff = (function() {
|
var COLLAPSED_HTML, ERROR_HTML, LOADING_HTML, WRAPPER;
|
||||||
var COLLAPSED_HTML, ERROR_HTML, LOADING_HTML, WRAPPER;
|
|
||||||
|
|
||||||
WRAPPER = '<div class="diff-content"></div>';
|
WRAPPER = '<div class="diff-content"></div>';
|
||||||
|
|
||||||
LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
|
LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||||
|
|
||||||
ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
|
ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
|
||||||
|
|
||||||
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
|
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
|
||||||
|
|
||||||
function SingleFileDiff(file) {
|
function SingleFileDiff(file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.toggleDiff = this.toggleDiff.bind(this);
|
this.toggleDiff = this.toggleDiff.bind(this);
|
||||||
this.content = $('.diff-content', this.file);
|
this.content = $('.diff-content', this.file);
|
||||||
this.$toggleIcon = $('.diff-toggle-caret', this.file);
|
this.$toggleIcon = $('.diff-toggle-caret', this.file);
|
||||||
this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path');
|
this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path');
|
||||||
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) {
|
|
||||||
this.toggleDiff($(e.target));
|
|
||||||
}).bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleFileDiff.prototype.toggleDiff = function($target, cb) {
|
$('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
|
||||||
if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
|
this.toggleDiff($(e.target));
|
||||||
this.isOpen = !this.isOpen;
|
}).bind(this));
|
||||||
if (!this.isOpen && !this.hasError) {
|
}
|
||||||
this.content.hide();
|
|
||||||
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
|
|
||||||
this.collapsedContent.show();
|
|
||||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
|
||||||
gl.diffNotesCompileComponents();
|
|
||||||
}
|
|
||||||
} else if (this.content) {
|
|
||||||
this.collapsedContent.hide();
|
|
||||||
this.content.show();
|
|
||||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
|
||||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
|
||||||
gl.diffNotesCompileComponents();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
|
||||||
return this.getContentHTML(cb);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SingleFileDiff.prototype.getContentHTML = function(cb) {
|
SingleFileDiff.prototype.toggleDiff = function($target, cb) {
|
||||||
|
if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
if (!this.isOpen && !this.hasError) {
|
||||||
|
this.content.hide();
|
||||||
|
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
|
||||||
|
this.collapsedContent.show();
|
||||||
|
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||||
|
gl.diffNotesCompileComponents();
|
||||||
|
}
|
||||||
|
} else if (this.content) {
|
||||||
this.collapsedContent.hide();
|
this.collapsedContent.hide();
|
||||||
this.loadingContent.show();
|
this.content.show();
|
||||||
$.get(this.diffForPath, (function(_this) {
|
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||||
return function(data) {
|
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||||
_this.loadingContent.hide();
|
gl.diffNotesCompileComponents();
|
||||||
if (data.html) {
|
|
||||||
_this.content = $(data.html);
|
|
||||||
_this.content.syntaxHighlight();
|
|
||||||
} else {
|
|
||||||
_this.hasError = true;
|
|
||||||
_this.content = $(ERROR_HTML);
|
|
||||||
}
|
|
||||||
_this.collapsedContent.after(_this.content);
|
|
||||||
|
|
||||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
|
||||||
gl.diffNotesCompileComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
FilesCommentButton.init($(_this.file));
|
|
||||||
|
|
||||||
if (cb) cb();
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
return SingleFileDiff;
|
|
||||||
})();
|
|
||||||
|
|
||||||
$.fn.singleFileDiff = function() {
|
|
||||||
return this.each(function() {
|
|
||||||
if (!$.data(this, 'singleFileDiff')) {
|
|
||||||
return $.data(this, 'singleFileDiff', new window.SingleFileDiff(this));
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||||
|
return this.getContentHTML(cb);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}).call(window);
|
|
||||||
|
SingleFileDiff.prototype.getContentHTML = function(cb) {
|
||||||
|
this.collapsedContent.hide();
|
||||||
|
this.loadingContent.show();
|
||||||
|
$.get(this.diffForPath, (function(_this) {
|
||||||
|
return function(data) {
|
||||||
|
_this.loadingContent.hide();
|
||||||
|
if (data.html) {
|
||||||
|
_this.content = $(data.html);
|
||||||
|
_this.content.syntaxHighlight();
|
||||||
|
} else {
|
||||||
|
_this.hasError = true;
|
||||||
|
_this.content = $(ERROR_HTML);
|
||||||
|
}
|
||||||
|
_this.collapsedContent.after(_this.content);
|
||||||
|
|
||||||
|
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||||
|
gl.diffNotesCompileComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
FilesCommentButton.init($(_this.file));
|
||||||
|
|
||||||
|
if (cb) cb();
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
return SingleFileDiff;
|
||||||
|
})();
|
||||||
|
|
||||||
|
$.fn.singleFileDiff = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
if (!$.data(this, 'singleFileDiff')) {
|
||||||
|
return $.data(this, 'singleFileDiff', new window.SingleFileDiff(this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -1,158 +1,157 @@
|
||||||
/*
|
/**
|
||||||
* Instances of SmartInterval extend the functionality of `setInterval`, make it configurable
|
* Instances of SmartInterval extend the functionality of `setInterval`, make it configurable
|
||||||
* and controllable by a public API.
|
* and controllable by a public API.
|
||||||
*
|
*/
|
||||||
* */
|
|
||||||
|
|
||||||
(() => {
|
class SmartInterval {
|
||||||
class SmartInterval {
|
/**
|
||||||
/**
|
* @param { function } opts.callback Function to be called on each iteration (required)
|
||||||
* @param { function } opts.callback Function to be called on each iteration (required)
|
* @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
|
||||||
* @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
|
* @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
|
||||||
* @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
|
* @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
|
||||||
* @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
|
* when the page is hidden
|
||||||
* when the page is hidden
|
* @param { integer } opts.incrementByFactorOf `currentInterval` is incremented by this factor
|
||||||
* @param { integer } opts.incrementByFactorOf `currentInterval` is incremented by this factor
|
* @param { boolean } opts.lazyStart Configure if timer is initialized on
|
||||||
* @param { boolean } opts.lazyStart Configure if timer is initialized on
|
* instantiation or lazily
|
||||||
* instantiation or lazily
|
* @param { boolean } opts.immediateExecution Configure if callback should
|
||||||
* @param { boolean } opts.immediateExecution Configure if callback should
|
* be executed before the first interval.
|
||||||
* be executed before the first interval.
|
*/
|
||||||
*/
|
constructor(opts = {}) {
|
||||||
constructor(opts = {}) {
|
this.cfg = {
|
||||||
this.cfg = {
|
callback: opts.callback,
|
||||||
callback: opts.callback,
|
startingInterval: opts.startingInterval,
|
||||||
startingInterval: opts.startingInterval,
|
maxInterval: opts.maxInterval,
|
||||||
maxInterval: opts.maxInterval,
|
hiddenInterval: opts.hiddenInterval,
|
||||||
hiddenInterval: opts.hiddenInterval,
|
incrementByFactorOf: opts.incrementByFactorOf,
|
||||||
incrementByFactorOf: opts.incrementByFactorOf,
|
lazyStart: opts.lazyStart,
|
||||||
lazyStart: opts.lazyStart,
|
immediateExecution: opts.immediateExecution,
|
||||||
immediateExecution: opts.immediateExecution,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
intervalId: null,
|
intervalId: null,
|
||||||
currentInterval: this.cfg.startingInterval,
|
currentInterval: this.cfg.startingInterval,
|
||||||
pageVisibility: 'visible',
|
pageVisibility: 'visible',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.initInterval();
|
this.initInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public */
|
||||||
|
|
||||||
|
start() {
|
||||||
|
const cfg = this.cfg;
|
||||||
|
const state = this.state;
|
||||||
|
|
||||||
|
if (cfg.immediateExecution) {
|
||||||
|
cfg.immediateExecution = false;
|
||||||
|
cfg.callback();
|
||||||
}
|
}
|
||||||
/* public */
|
|
||||||
|
|
||||||
start() {
|
state.intervalId = window.setInterval(() => {
|
||||||
const cfg = this.cfg;
|
cfg.callback();
|
||||||
const state = this.state;
|
|
||||||
|
|
||||||
if (cfg.immediateExecution) {
|
if (this.getCurrentInterval() === cfg.maxInterval) {
|
||||||
cfg.immediateExecution = false;
|
return;
|
||||||
cfg.callback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.intervalId = window.setInterval(() => {
|
this.incrementInterval();
|
||||||
cfg.callback();
|
this.resume();
|
||||||
|
}, this.getCurrentInterval());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.getCurrentInterval() === cfg.maxInterval) {
|
// cancel the existing timer, setting the currentInterval back to startingInterval
|
||||||
return;
|
cancel() {
|
||||||
}
|
this.setCurrentInterval(this.cfg.startingInterval);
|
||||||
|
this.stopTimer();
|
||||||
|
}
|
||||||
|
|
||||||
this.incrementInterval();
|
onVisibilityHidden() {
|
||||||
this.resume();
|
if (this.cfg.hiddenInterval) {
|
||||||
}, this.getCurrentInterval());
|
this.setCurrentInterval(this.cfg.hiddenInterval);
|
||||||
}
|
this.resume();
|
||||||
|
} else {
|
||||||
// cancel the existing timer, setting the currentInterval back to startingInterval
|
|
||||||
cancel() {
|
|
||||||
this.setCurrentInterval(this.cfg.startingInterval);
|
|
||||||
this.stopTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
onVisibilityHidden() {
|
|
||||||
if (this.cfg.hiddenInterval) {
|
|
||||||
this.setCurrentInterval(this.cfg.hiddenInterval);
|
|
||||||
this.resume();
|
|
||||||
} else {
|
|
||||||
this.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start a timer, using the existing interval
|
|
||||||
resume() {
|
|
||||||
this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
onVisibilityVisible() {
|
|
||||||
this.cancel();
|
this.cancel();
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.cancel();
|
|
||||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
|
||||||
$(document).off('visibilitychange').off('beforeunload');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* private */
|
|
||||||
|
|
||||||
initInterval() {
|
|
||||||
const cfg = this.cfg;
|
|
||||||
|
|
||||||
if (!cfg.lazyStart) {
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initVisibilityChangeHandling();
|
|
||||||
this.initPageUnloadHandling();
|
|
||||||
}
|
|
||||||
|
|
||||||
initVisibilityChangeHandling() {
|
|
||||||
// cancel interval when tab no longer shown (prevents cached pages from polling)
|
|
||||||
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
initPageUnloadHandling() {
|
|
||||||
// TODO: Consider refactoring in light of turbolinks removal.
|
|
||||||
// prevent interval continuing after page change, when kept in cache by Turbolinks
|
|
||||||
$(document).on('beforeunload', () => this.cancel());
|
|
||||||
}
|
|
||||||
|
|
||||||
handleVisibilityChange(e) {
|
|
||||||
this.state.pageVisibility = e.target.visibilityState;
|
|
||||||
const intervalAction = this.isPageVisible() ?
|
|
||||||
this.onVisibilityVisible :
|
|
||||||
this.onVisibilityHidden;
|
|
||||||
|
|
||||||
intervalAction.apply(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentInterval() {
|
|
||||||
return this.state.currentInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentInterval(newInterval) {
|
|
||||||
this.state.currentInterval = newInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementInterval() {
|
|
||||||
const cfg = this.cfg;
|
|
||||||
const currentInterval = this.getCurrentInterval();
|
|
||||||
if (cfg.hiddenInterval && !this.isPageVisible()) return;
|
|
||||||
let nextInterval = currentInterval * cfg.incrementByFactorOf;
|
|
||||||
|
|
||||||
if (nextInterval > cfg.maxInterval) {
|
|
||||||
nextInterval = cfg.maxInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setCurrentInterval(nextInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
isPageVisible() { return this.state.pageVisibility === 'visible'; }
|
|
||||||
|
|
||||||
stopTimer() {
|
|
||||||
const state = this.state;
|
|
||||||
|
|
||||||
state.intervalId = window.clearInterval(state.intervalId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gl.SmartInterval = SmartInterval;
|
|
||||||
})(window.gl || (window.gl = {}));
|
// start a timer, using the existing interval
|
||||||
|
resume() {
|
||||||
|
this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibilityVisible() {
|
||||||
|
this.cancel();
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.cancel();
|
||||||
|
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||||
|
$(document).off('visibilitychange').off('beforeunload');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* private */
|
||||||
|
|
||||||
|
initInterval() {
|
||||||
|
const cfg = this.cfg;
|
||||||
|
|
||||||
|
if (!cfg.lazyStart) {
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initVisibilityChangeHandling();
|
||||||
|
this.initPageUnloadHandling();
|
||||||
|
}
|
||||||
|
|
||||||
|
initVisibilityChangeHandling() {
|
||||||
|
// cancel interval when tab no longer shown (prevents cached pages from polling)
|
||||||
|
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
initPageUnloadHandling() {
|
||||||
|
// TODO: Consider refactoring in light of turbolinks removal.
|
||||||
|
// prevent interval continuing after page change, when kept in cache by Turbolinks
|
||||||
|
$(document).on('beforeunload', () => this.cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
handleVisibilityChange(e) {
|
||||||
|
this.state.pageVisibility = e.target.visibilityState;
|
||||||
|
const intervalAction = this.isPageVisible() ?
|
||||||
|
this.onVisibilityVisible :
|
||||||
|
this.onVisibilityHidden;
|
||||||
|
|
||||||
|
intervalAction.apply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentInterval() {
|
||||||
|
return this.state.currentInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentInterval(newInterval) {
|
||||||
|
this.state.currentInterval = newInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
incrementInterval() {
|
||||||
|
const cfg = this.cfg;
|
||||||
|
const currentInterval = this.getCurrentInterval();
|
||||||
|
if (cfg.hiddenInterval && !this.isPageVisible()) return;
|
||||||
|
let nextInterval = currentInterval * cfg.incrementByFactorOf;
|
||||||
|
|
||||||
|
if (nextInterval > cfg.maxInterval) {
|
||||||
|
nextInterval = cfg.maxInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setCurrentInterval(nextInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
isPageVisible() { return this.state.pageVisibility === 'visible'; }
|
||||||
|
|
||||||
|
stopTimer() {
|
||||||
|
const state = this.state;
|
||||||
|
|
||||||
|
state.intervalId = window.clearInterval(state.intervalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gl.SmartInterval = SmartInterval;
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
/* eslint-disable arrow-parens, no-param-reassign, space-before-function-paren, func-names, no-var, max-len */
|
/* eslint-disable arrow-parens, no-param-reassign, space-before-function-paren, func-names, no-var, max-len */
|
||||||
|
|
||||||
(global => {
|
window.gl.SnippetsList = function() {
|
||||||
global.gl = global.gl || {};
|
var $holder = $('.snippets-list-holder');
|
||||||
|
|
||||||
gl.SnippetsList = function() {
|
$holder.find('.pagination').on('ajax:success', (e, data) => {
|
||||||
var $holder = $('.snippets-list-holder');
|
$holder.replaceWith(data.html);
|
||||||
|
});
|
||||||
$holder.find('.pagination').on('ajax:success', (e, data) => {
|
};
|
||||||
$holder.replaceWith(data.html);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
})(window);
|
|
||||||
|
|
|
@ -1,30 +1,28 @@
|
||||||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */
|
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */
|
||||||
/* global Flash */
|
/* global Flash */
|
||||||
|
|
||||||
(function() {
|
window.Star = (function() {
|
||||||
this.Star = (function() {
|
function Star() {
|
||||||
function Star() {
|
$('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) {
|
||||||
$('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) {
|
var $starIcon, $starSpan, $this, toggleStar;
|
||||||
var $starIcon, $starSpan, $this, toggleStar;
|
$this = $(this);
|
||||||
$this = $(this);
|
$starSpan = $this.find('span');
|
||||||
$starSpan = $this.find('span');
|
$starIcon = $this.find('i');
|
||||||
$starIcon = $this.find('i');
|
toggleStar = function(isStarred) {
|
||||||
toggleStar = function(isStarred) {
|
$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('Star');
|
||||||
$starSpan.removeClass('starred').text('Star');
|
$starIcon.removeClass('fa-star').addClass('fa-star-o');
|
||||||
$starIcon.removeClass('fa-star').addClass('fa-star-o');
|
} else {
|
||||||
} else {
|
$starSpan.addClass('starred').text('Unstar');
|
||||||
$starSpan.addClass('starred').text('Unstar');
|
$starIcon.removeClass('fa-star-o').addClass('fa-star');
|
||||||
$starIcon.removeClass('fa-star-o').addClass('fa-star');
|
}
|
||||||
}
|
};
|
||||||
};
|
toggleStar($starSpan.hasClass('starred'));
|
||||||
toggleStar($starSpan.hasClass('starred'));
|
}).on('ajax:error', function(e, xhr, status, error) {
|
||||||
}).on('ajax:error', function(e, xhr, status, error) {
|
new Flash('Star toggle failed. Try again later.', 'alert');
|
||||||
new Flash('Star toggle failed. Try again later.', 'alert');
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return Star;
|
return Star;
|
||||||
})();
|
})();
|
||||||
}).call(window);
|
|
||||||
|
|
|
@ -1,47 +1,45 @@
|
||||||
(() => {
|
class Subscription {
|
||||||
class Subscription {
|
constructor(containerElm) {
|
||||||
constructor(containerElm) {
|
this.containerElm = containerElm;
|
||||||
this.containerElm = containerElm;
|
|
||||||
|
|
||||||
const subscribeButton = containerElm.querySelector('.js-subscribe-button');
|
const subscribeButton = containerElm.querySelector('.js-subscribe-button');
|
||||||
if (subscribeButton) {
|
if (subscribeButton) {
|
||||||
// remove class so we don't bind twice
|
// remove class so we don't bind twice
|
||||||
subscribeButton.classList.remove('js-subscribe-button');
|
subscribeButton.classList.remove('js-subscribe-button');
|
||||||
subscribeButton.addEventListener('click', this.toggleSubscription.bind(this));
|
subscribeButton.addEventListener('click', this.toggleSubscription.bind(this));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSubscription(event) {
|
|
||||||
const button = event.currentTarget;
|
|
||||||
const buttonSpan = button.querySelector('span');
|
|
||||||
if (!buttonSpan || button.classList.contains('disabled')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
button.classList.add('disabled');
|
|
||||||
|
|
||||||
const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe';
|
|
||||||
const toggleActionUrl = this.containerElm.dataset.url;
|
|
||||||
|
|
||||||
$.post(toggleActionUrl, () => {
|
|
||||||
button.classList.remove('disabled');
|
|
||||||
|
|
||||||
// hack to allow this to work with the issue boards Vue object
|
|
||||||
if (document.querySelector('html').classList.contains('issue-boards-page')) {
|
|
||||||
gl.issueBoards.boardStoreIssueSet(
|
|
||||||
'subscribed',
|
|
||||||
!gl.issueBoards.BoardsStore.detail.issue.subscribed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static bindAll(selector) {
|
|
||||||
[].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.gl = window.gl || {};
|
toggleSubscription(event) {
|
||||||
window.gl.Subscription = Subscription;
|
const button = event.currentTarget;
|
||||||
})();
|
const buttonSpan = button.querySelector('span');
|
||||||
|
if (!buttonSpan || button.classList.contains('disabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
button.classList.add('disabled');
|
||||||
|
|
||||||
|
const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe';
|
||||||
|
const toggleActionUrl = this.containerElm.dataset.url;
|
||||||
|
|
||||||
|
$.post(toggleActionUrl, () => {
|
||||||
|
button.classList.remove('disabled');
|
||||||
|
|
||||||
|
// hack to allow this to work with the issue boards Vue object
|
||||||
|
if (document.querySelector('html').classList.contains('issue-boards-page')) {
|
||||||
|
gl.issueBoards.boardStoreIssueSet(
|
||||||
|
'subscribed',
|
||||||
|
!gl.issueBoards.BoardsStore.detail.issue.subscribed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static bindAll(selector) {
|
||||||
|
[].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gl = window.gl || {};
|
||||||
|
window.gl.Subscription = Subscription;
|
||||||
|
|
|
@ -1,34 +1,33 @@
|
||||||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */
|
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */
|
||||||
(function() {
|
|
||||||
this.SubscriptionSelect = (function() {
|
|
||||||
function SubscriptionSelect() {
|
|
||||||
$('.js-subscription-event').each(function(i, el) {
|
|
||||||
var fieldName;
|
|
||||||
fieldName = $(el).data("field-name");
|
|
||||||
return $(el).glDropdown({
|
|
||||||
selectable: true,
|
|
||||||
fieldName: fieldName,
|
|
||||||
toggleLabel: (function(_this) {
|
|
||||||
return function(selected, el, instance) {
|
|
||||||
var $item, label;
|
|
||||||
label = 'Subscription';
|
|
||||||
$item = instance.dropdown.find('.is-active');
|
|
||||||
if ($item.length) {
|
|
||||||
label = $item.text();
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
};
|
|
||||||
})(this),
|
|
||||||
clicked: function(options) {
|
|
||||||
return options.e.preventDefault();
|
|
||||||
},
|
|
||||||
id: function(obj, el) {
|
|
||||||
return $(el).data("id");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return SubscriptionSelect;
|
window.SubscriptionSelect = (function() {
|
||||||
})();
|
function SubscriptionSelect() {
|
||||||
}).call(window);
|
$('.js-subscription-event').each(function(i, el) {
|
||||||
|
var fieldName;
|
||||||
|
fieldName = $(el).data("field-name");
|
||||||
|
return $(el).glDropdown({
|
||||||
|
selectable: true,
|
||||||
|
fieldName: fieldName,
|
||||||
|
toggleLabel: (function(_this) {
|
||||||
|
return function(selected, el, instance) {
|
||||||
|
var $item, label;
|
||||||
|
label = 'Subscription';
|
||||||
|
$item = instance.dropdown.find('.is-active');
|
||||||
|
if ($item.length) {
|
||||||
|
label = $item.text();
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
clicked: function(options) {
|
||||||
|
return options.e.preventDefault();
|
||||||
|
},
|
||||||
|
id: function(obj, el) {
|
||||||
|
return $(el).data("id");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return SubscriptionSelect;
|
||||||
|
})();
|
||||||
|
|
|
@ -9,19 +9,18 @@
|
||||||
//
|
//
|
||||||
// <div class="js-syntax-highlight"></div>
|
// <div class="js-syntax-highlight"></div>
|
||||||
//
|
//
|
||||||
(function() {
|
|
||||||
$.fn.syntaxHighlight = function() {
|
|
||||||
var $children;
|
|
||||||
|
|
||||||
if ($(this).hasClass('js-syntax-highlight')) {
|
$.fn.syntaxHighlight = function() {
|
||||||
// Given the element itself, apply highlighting
|
var $children;
|
||||||
return $(this).addClass(gon.user_color_scheme);
|
|
||||||
} else {
|
if ($(this).hasClass('js-syntax-highlight')) {
|
||||||
// Given a parent element, recurse to any of its applicable children
|
// Given the element itself, apply highlighting
|
||||||
$children = $(this).find('.js-syntax-highlight');
|
return $(this).addClass(gon.user_color_scheme);
|
||||||
if ($children.length) {
|
} else {
|
||||||
return $children.syntaxHighlight();
|
// Given a parent element, recurse to any of its applicable children
|
||||||
}
|
$children = $(this).find('.js-syntax-highlight');
|
||||||
|
if ($children.length) {
|
||||||
|
return $children.syntaxHighlight();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}).call(window);
|
};
|
||||||
|
|
|
@ -1,68 +1,66 @@
|
||||||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, max-len */
|
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, max-len */
|
||||||
|
|
||||||
(function() {
|
window.TreeView = (function() {
|
||||||
this.TreeView = (function() {
|
function TreeView() {
|
||||||
function 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');
|
if (!$clickedEl.is('a') && !$clickedEl.is('.str-truncated')) {
|
||||||
if (!$clickedEl.is('a') && !$clickedEl.is('.str-truncated')) {
|
if (e.metaKey || e.which === 2) {
|
||||||
if (e.metaKey || e.which === 2) {
|
e.preventDefault();
|
||||||
e.preventDefault();
|
return window.open(path, '_blank');
|
||||||
return window.open(path, '_blank');
|
} else {
|
||||||
} else {
|
return gl.utils.visitUrl(path);
|
||||||
return gl.utils.visitUrl(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
// Show the "Loading commit data" for only the first element
|
});
|
||||||
$('span.log_loading:first').removeClass('hide');
|
// Show the "Loading commit data" for only the first element
|
||||||
}
|
$('span.log_loading:first').removeClass('hide');
|
||||||
|
}
|
||||||
|
|
||||||
TreeView.prototype.initKeyNav = function() {
|
TreeView.prototype.initKeyNav = function() {
|
||||||
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 (liSelected) {
|
||||||
|
next = liSelected.next();
|
||||||
|
if (next.length > 0) {
|
||||||
|
liSelected.removeClass("selected");
|
||||||
|
liSelected = next.addClass("selected");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
liSelected = li.eq(0).addClass("selected");
|
||||||
}
|
}
|
||||||
if (e.which === 40) {
|
return $(liSelected).focus();
|
||||||
if (liSelected) {
|
} else if (e.which === 38) {
|
||||||
next = liSelected.next();
|
if (liSelected) {
|
||||||
if (next.length > 0) {
|
next = liSelected.prev();
|
||||||
liSelected.removeClass("selected");
|
if (next.length > 0) {
|
||||||
liSelected = next.addClass("selected");
|
liSelected.removeClass("selected");
|
||||||
}
|
liSelected = next.addClass("selected");
|
||||||
} else {
|
|
||||||
liSelected = li.eq(0).addClass("selected");
|
|
||||||
}
|
|
||||||
return $(liSelected).focus();
|
|
||||||
} else if (e.which === 38) {
|
|
||||||
if (liSelected) {
|
|
||||||
next = liSelected.prev();
|
|
||||||
if (next.length > 0) {
|
|
||||||
liSelected.removeClass("selected");
|
|
||||||
liSelected = next.addClass("selected");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
liSelected = li.last().addClass("selected");
|
|
||||||
}
|
|
||||||
return $(liSelected).focus();
|
|
||||||
} else if (e.which === 13) {
|
|
||||||
path = $('.tree-item.selected .tree-item-file-name a').attr('href');
|
|
||||||
if (path) {
|
|
||||||
return gl.utils.visitUrl(path);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
liSelected = li.last().addClass("selected");
|
||||||
}
|
}
|
||||||
});
|
return $(liSelected).focus();
|
||||||
};
|
} else if (e.which === 13) {
|
||||||
|
path = $('.tree-item.selected .tree-item-file-name a').attr('href');
|
||||||
|
if (path) {
|
||||||
|
return gl.utils.visitUrl(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return TreeView;
|
return TreeView;
|
||||||
})();
|
})();
|
||||||
}).call(window);
|
|
||||||
|
|
|
@ -2,34 +2,35 @@
|
||||||
|
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
((global) => {
|
class User {
|
||||||
global.User = class {
|
constructor({ action }) {
|
||||||
constructor({ action }) {
|
this.action = action;
|
||||||
this.action = action;
|
this.placeProfileAvatarsToTop();
|
||||||
this.placeProfileAvatarsToTop();
|
this.initTabs();
|
||||||
this.initTabs();
|
this.hideProjectLimitMessage();
|
||||||
this.hideProjectLimitMessage();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
placeProfileAvatarsToTop() {
|
placeProfileAvatarsToTop() {
|
||||||
$('.profile-groups-avatars').tooltip({
|
$('.profile-groups-avatars').tooltip({
|
||||||
placement: 'top'
|
placement: 'top'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initTabs() {
|
initTabs() {
|
||||||
return new global.UserTabs({
|
return new window.gl.UserTabs({
|
||||||
parentEl: '.user-profile',
|
parentEl: '.user-profile',
|
||||||
action: this.action
|
action: this.action
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hideProjectLimitMessage() {
|
hideProjectLimitMessage() {
|
||||||
$('.hide-project-limit-message').on('click', e => {
|
$('.hide-project-limit-message').on('click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
Cookies.set('hide_project_limit_message', 'false');
|
Cookies.set('hide_project_limit_message', 'false');
|
||||||
$(this).parents('.project-limit-message').remove();
|
$(this).parents('.project-limit-message').remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
})(window.gl || (window.gl = {}));
|
|
||||||
|
window.gl = window.gl || {};
|
||||||
|
window.gl.User = User;
|
||||||
|
|
|
@ -59,117 +59,118 @@ content on the Users#show page.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
*/
|
*/
|
||||||
((global) => {
|
|
||||||
class UserTabs {
|
|
||||||
constructor ({ defaultAction, action, parentEl }) {
|
|
||||||
this.loaded = {};
|
|
||||||
this.defaultAction = defaultAction || 'activity';
|
|
||||||
this.action = action || this.defaultAction;
|
|
||||||
this.$parentEl = $(parentEl) || $(document);
|
|
||||||
this._location = window.location;
|
|
||||||
this.$parentEl.find('.nav-links a')
|
|
||||||
.each((i, navLink) => {
|
|
||||||
this.loaded[$(navLink).attr('data-action')] = false;
|
|
||||||
});
|
|
||||||
this.actions = Object.keys(this.loaded);
|
|
||||||
this.bindEvents();
|
|
||||||
|
|
||||||
if (this.action === 'show') {
|
class UserTabs {
|
||||||
this.action = this.defaultAction;
|
constructor ({ defaultAction, action, parentEl }) {
|
||||||
}
|
this.loaded = {};
|
||||||
|
this.defaultAction = defaultAction || 'activity';
|
||||||
this.activateTab(this.action);
|
this.action = action || this.defaultAction;
|
||||||
}
|
this.$parentEl = $(parentEl) || $(document);
|
||||||
|
this._location = window.location;
|
||||||
bindEvents() {
|
this.$parentEl.find('.nav-links a')
|
||||||
this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this);
|
.each((i, navLink) => {
|
||||||
|
this.loaded[$(navLink).attr('data-action')] = false;
|
||||||
this.$parentEl.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
|
|
||||||
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event));
|
|
||||||
|
|
||||||
this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeProjectsPage(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
$('.tab-pane.active').empty();
|
|
||||||
const endpoint = $(e.target).attr('href');
|
|
||||||
this.loadTab(this.getCurrentAction(), endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
tabShown(event) {
|
|
||||||
const $target = $(event.target);
|
|
||||||
const action = $target.data('action');
|
|
||||||
const source = $target.attr('href');
|
|
||||||
const endpoint = $target.data('endpoint');
|
|
||||||
this.setTab(action, endpoint);
|
|
||||||
return this.setCurrentAction(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
activateTab(action) {
|
|
||||||
return this.$parentEl.find(`.nav-links .js-${action}-tab a`)
|
|
||||||
.tab('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
setTab(action, endpoint) {
|
|
||||||
if (this.loaded[action]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === 'activity') {
|
|
||||||
this.loadActivities();
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
|
|
||||||
if (loadableActions.indexOf(action) > -1) {
|
|
||||||
return this.loadTab(action, endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadTab(action, endpoint) {
|
|
||||||
return $.ajax({
|
|
||||||
beforeSend: () => this.toggleLoading(true),
|
|
||||||
complete: () => this.toggleLoading(false),
|
|
||||||
dataType: 'json',
|
|
||||||
type: 'GET',
|
|
||||||
url: endpoint,
|
|
||||||
success: (data) => {
|
|
||||||
const tabSelector = `div#${action}`;
|
|
||||||
this.$parentEl.find(tabSelector).html(data.html);
|
|
||||||
this.loaded[action] = true;
|
|
||||||
return gl.utils.localTimeAgo($('.js-timeago', tabSelector));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
this.actions = Object.keys(this.loaded);
|
||||||
|
this.bindEvents();
|
||||||
|
|
||||||
|
if (this.action === 'show') {
|
||||||
|
this.action = this.defaultAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadActivities() {
|
this.activateTab(this.action);
|
||||||
if (this.loaded['activity']) {
|
}
|
||||||
return;
|
|
||||||
}
|
bindEvents() {
|
||||||
const $calendarWrap = this.$parentEl.find('.user-calendar');
|
this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this);
|
||||||
$calendarWrap.load($calendarWrap.data('href'));
|
|
||||||
new gl.Activities();
|
this.$parentEl.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
|
||||||
return this.loaded['activity'] = true;
|
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event));
|
||||||
|
|
||||||
|
this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeProjectsPage(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$('.tab-pane.active').empty();
|
||||||
|
const endpoint = $(e.target).attr('href');
|
||||||
|
this.loadTab(this.getCurrentAction(), endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
tabShown(event) {
|
||||||
|
const $target = $(event.target);
|
||||||
|
const action = $target.data('action');
|
||||||
|
const source = $target.attr('href');
|
||||||
|
const endpoint = $target.data('endpoint');
|
||||||
|
this.setTab(action, endpoint);
|
||||||
|
return this.setCurrentAction(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
activateTab(action) {
|
||||||
|
return this.$parentEl.find(`.nav-links .js-${action}-tab a`)
|
||||||
|
.tab('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
setTab(action, endpoint) {
|
||||||
|
if (this.loaded[action]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action === 'activity') {
|
||||||
|
this.loadActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLoading(status) {
|
const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
|
||||||
return this.$parentEl.find('.loading-status .loading')
|
if (loadableActions.indexOf(action) > -1) {
|
||||||
.toggle(status);
|
return this.loadTab(action, endpoint);
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentAction(source) {
|
|
||||||
let new_state = source;
|
|
||||||
new_state = new_state.replace(/\/+$/, '');
|
|
||||||
new_state += this._location.search + this._location.hash;
|
|
||||||
history.replaceState({
|
|
||||||
url: new_state
|
|
||||||
}, document.title, new_state);
|
|
||||||
return new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentAction() {
|
|
||||||
return this.$parentEl.find('.nav-links .active a').data('action');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
global.UserTabs = UserTabs;
|
|
||||||
})(window.gl || (window.gl = {}));
|
loadTab(action, endpoint) {
|
||||||
|
return $.ajax({
|
||||||
|
beforeSend: () => this.toggleLoading(true),
|
||||||
|
complete: () => this.toggleLoading(false),
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'GET',
|
||||||
|
url: endpoint,
|
||||||
|
success: (data) => {
|
||||||
|
const tabSelector = `div#${action}`;
|
||||||
|
this.$parentEl.find(tabSelector).html(data.html);
|
||||||
|
this.loaded[action] = true;
|
||||||
|
return gl.utils.localTimeAgo($('.js-timeago', tabSelector));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadActivities() {
|
||||||
|
if (this.loaded['activity']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const $calendarWrap = this.$parentEl.find('.user-calendar');
|
||||||
|
$calendarWrap.load($calendarWrap.data('href'));
|
||||||
|
new gl.Activities();
|
||||||
|
return this.loaded['activity'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLoading(status) {
|
||||||
|
return this.$parentEl.find('.loading-status .loading')
|
||||||
|
.toggle(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentAction(source) {
|
||||||
|
let new_state = source;
|
||||||
|
new_state = new_state.replace(/\/+$/, '');
|
||||||
|
new_state += this._location.search + this._location.hash;
|
||||||
|
history.replaceState({
|
||||||
|
url: new_state
|
||||||
|
}, document.title, new_state);
|
||||||
|
return new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentAction() {
|
||||||
|
return this.$parentEl.find('.nav-links .active a').data('action');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gl = window.gl || {};
|
||||||
|
window.gl.UserTabs = UserTabs;
|
||||||
|
|
|
@ -1,135 +1,133 @@
|
||||||
/* eslint-disable comma-dangle, consistent-return, class-methods-use-this, arrow-parens, no-param-reassign, max-len */
|
/* eslint-disable comma-dangle, consistent-return, class-methods-use-this, arrow-parens, no-param-reassign, max-len */
|
||||||
|
|
||||||
((global) => {
|
const debounceTimeoutDuration = 1000;
|
||||||
const debounceTimeoutDuration = 1000;
|
const invalidInputClass = 'gl-field-error-outline';
|
||||||
const invalidInputClass = 'gl-field-error-outline';
|
const successInputClass = 'gl-field-success-outline';
|
||||||
const successInputClass = 'gl-field-success-outline';
|
const unavailableMessageSelector = '.username .validation-error';
|
||||||
const unavailableMessageSelector = '.username .validation-error';
|
const successMessageSelector = '.username .validation-success';
|
||||||
const successMessageSelector = '.username .validation-success';
|
const pendingMessageSelector = '.username .validation-pending';
|
||||||
const pendingMessageSelector = '.username .validation-pending';
|
const invalidMessageSelector = '.username .gl-field-error';
|
||||||
const invalidMessageSelector = '.username .gl-field-error';
|
|
||||||
|
|
||||||
class UsernameValidator {
|
class UsernameValidator {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.inputElement = $('#new_user_username');
|
this.inputElement = $('#new_user_username');
|
||||||
this.inputDomElement = this.inputElement.get(0);
|
this.inputDomElement = this.inputElement.get(0);
|
||||||
this.state = {
|
this.state = {
|
||||||
available: false,
|
available: false,
|
||||||
valid: false,
|
valid: false,
|
||||||
pending: false,
|
pending: false,
|
||||||
empty: true
|
empty: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const debounceTimeout = _.debounce((username) => {
|
const debounceTimeout = _.debounce((username) => {
|
||||||
this.validateUsername(username);
|
this.validateUsername(username);
|
||||||
}, debounceTimeoutDuration);
|
}, debounceTimeoutDuration);
|
||||||
|
|
||||||
this.inputElement.on('keyup.username_check', () => {
|
this.inputElement.on('keyup.username_check', () => {
|
||||||
const username = this.inputElement.val();
|
const username = this.inputElement.val();
|
||||||
|
|
||||||
this.state.valid = this.inputDomElement.validity.valid;
|
this.state.valid = this.inputDomElement.validity.valid;
|
||||||
this.state.empty = !username.length;
|
this.state.empty = !username.length;
|
||||||
|
|
||||||
if (this.state.valid) {
|
|
||||||
return debounceTimeout(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderState();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Override generic field validation
|
|
||||||
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
renderState() {
|
|
||||||
// Clear all state
|
|
||||||
this.clearFieldValidationState();
|
|
||||||
|
|
||||||
if (this.state.valid && this.state.available) {
|
|
||||||
return this.setSuccessState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.empty) {
|
|
||||||
return this.clearFieldValidationState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.pending) {
|
|
||||||
return this.setPendingState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.state.available) {
|
|
||||||
return this.setUnavailableState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.state.valid) {
|
|
||||||
return this.setInvalidState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interceptInvalid(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
validateUsername(username) {
|
|
||||||
if (this.state.valid) {
|
if (this.state.valid) {
|
||||||
this.state.pending = true;
|
return debounceTimeout(username);
|
||||||
this.state.available = false;
|
|
||||||
this.renderState();
|
|
||||||
return $.ajax({
|
|
||||||
type: 'GET',
|
|
||||||
url: `${gon.relative_url_root}/users/${username}/exists`,
|
|
||||||
dataType: 'json',
|
|
||||||
success: (res) => this.setAvailabilityState(res.exists)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
setAvailabilityState(usernameTaken) {
|
|
||||||
if (usernameTaken) {
|
|
||||||
this.state.valid = false;
|
|
||||||
this.state.available = false;
|
|
||||||
} else {
|
|
||||||
this.state.available = true;
|
|
||||||
}
|
|
||||||
this.state.pending = false;
|
|
||||||
this.renderState();
|
this.renderState();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Override generic field validation
|
||||||
|
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderState() {
|
||||||
|
// Clear all state
|
||||||
|
this.clearFieldValidationState();
|
||||||
|
|
||||||
|
if (this.state.valid && this.state.available) {
|
||||||
|
return this.setSuccessState();
|
||||||
}
|
}
|
||||||
|
|
||||||
clearFieldValidationState() {
|
if (this.state.empty) {
|
||||||
this.inputElement.siblings('p').hide();
|
return this.clearFieldValidationState();
|
||||||
|
|
||||||
this.inputElement.removeClass(invalidInputClass)
|
|
||||||
.removeClass(successInputClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setUnavailableState() {
|
if (this.state.pending) {
|
||||||
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
|
return this.setPendingState();
|
||||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
|
||||||
$usernameUnavailableMessage.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setSuccessState() {
|
if (!this.state.available) {
|
||||||
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
|
return this.setUnavailableState();
|
||||||
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
|
|
||||||
$usernameSuccessMessage.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPendingState() {
|
if (!this.state.valid) {
|
||||||
const $usernamePendingMessage = $(pendingMessageSelector);
|
return this.setInvalidState();
|
||||||
if (this.state.pending) {
|
|
||||||
$usernamePendingMessage.show();
|
|
||||||
} else {
|
|
||||||
$usernamePendingMessage.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInvalidState() {
|
|
||||||
const $inputErrorMessage = $(invalidMessageSelector);
|
|
||||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
|
||||||
$inputErrorMessage.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global.UsernameValidator = UsernameValidator;
|
interceptInvalid(event) {
|
||||||
})(window);
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
validateUsername(username) {
|
||||||
|
if (this.state.valid) {
|
||||||
|
this.state.pending = true;
|
||||||
|
this.state.available = false;
|
||||||
|
this.renderState();
|
||||||
|
return $.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: `${gon.relative_url_root}/users/${username}/exists`,
|
||||||
|
dataType: 'json',
|
||||||
|
success: (res) => this.setAvailabilityState(res.exists)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAvailabilityState(usernameTaken) {
|
||||||
|
if (usernameTaken) {
|
||||||
|
this.state.valid = false;
|
||||||
|
this.state.available = false;
|
||||||
|
} else {
|
||||||
|
this.state.available = true;
|
||||||
|
}
|
||||||
|
this.state.pending = false;
|
||||||
|
this.renderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFieldValidationState() {
|
||||||
|
this.inputElement.siblings('p').hide();
|
||||||
|
|
||||||
|
this.inputElement.removeClass(invalidInputClass)
|
||||||
|
.removeClass(successInputClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUnavailableState() {
|
||||||
|
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
|
||||||
|
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||||
|
$usernameUnavailableMessage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
setSuccessState() {
|
||||||
|
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
|
||||||
|
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
|
||||||
|
$usernameSuccessMessage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
setPendingState() {
|
||||||
|
const $usernamePendingMessage = $(pendingMessageSelector);
|
||||||
|
if (this.state.pending) {
|
||||||
|
$usernamePendingMessage.show();
|
||||||
|
} else {
|
||||||
|
$usernamePendingMessage.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInvalidState() {
|
||||||
|
const $inputErrorMessage = $(invalidMessageSelector);
|
||||||
|
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||||
|
$inputErrorMessage.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.UsernameValidator = UsernameValidator;
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
(() => {
|
class VisibilitySelect {
|
||||||
const gl = window.gl || (window.gl = {});
|
constructor(container) {
|
||||||
|
if (!container) throw new Error('VisibilitySelect requires a container element as argument 1');
|
||||||
|
this.container = container;
|
||||||
|
this.helpBlock = this.container.querySelector('.help-block');
|
||||||
|
this.select = this.container.querySelector('select');
|
||||||
|
}
|
||||||
|
|
||||||
class VisibilitySelect {
|
init() {
|
||||||
constructor(container) {
|
if (this.select) {
|
||||||
if (!container) throw new Error('VisibilitySelect requires a container element as argument 1');
|
this.updateHelpText();
|
||||||
this.container = container;
|
this.select.addEventListener('change', this.updateHelpText.bind(this));
|
||||||
this.helpBlock = this.container.querySelector('.help-block');
|
} else {
|
||||||
this.select = this.container.querySelector('select');
|
this.helpBlock.textContent = this.container.querySelector('.js-locked').dataset.helpBlock;
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.select) {
|
|
||||||
this.updateHelpText();
|
|
||||||
this.select.addEventListener('change', this.updateHelpText.bind(this));
|
|
||||||
} else {
|
|
||||||
this.helpBlock.textContent = this.container.querySelector('.js-locked').dataset.helpBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateHelpText() {
|
|
||||||
this.helpBlock.textContent = this.select.querySelector('option:checked').dataset.description;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.VisibilitySelect = VisibilitySelect;
|
updateHelpText() {
|
||||||
})();
|
this.helpBlock.textContent = this.select.querySelector('option:checked').dataset.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gl = window.gl || {};
|
||||||
|
window.gl.VisibilitySelect = VisibilitySelect;
|
||||||
|
|
|
@ -4,66 +4,65 @@
|
||||||
import 'vendor/jquery.nicescroll';
|
import 'vendor/jquery.nicescroll';
|
||||||
import './breakpoints';
|
import './breakpoints';
|
||||||
|
|
||||||
((global) => {
|
class Wikis {
|
||||||
class Wikis {
|
constructor() {
|
||||||
constructor() {
|
this.bp = Breakpoints.get();
|
||||||
this.bp = Breakpoints.get();
|
this.sidebarEl = document.querySelector('.js-wiki-sidebar');
|
||||||
this.sidebarEl = document.querySelector('.js-wiki-sidebar');
|
this.sidebarExpanded = false;
|
||||||
this.sidebarExpanded = false;
|
$(this.sidebarEl).niceScroll();
|
||||||
$(this.sidebarEl).niceScroll();
|
|
||||||
|
|
||||||
const sidebarToggles = document.querySelectorAll('.js-sidebar-wiki-toggle');
|
const sidebarToggles = document.querySelectorAll('.js-sidebar-wiki-toggle');
|
||||||
for (let i = 0; i < sidebarToggles.length; i += 1) {
|
for (let i = 0; i < sidebarToggles.length; i += 1) {
|
||||||
sidebarToggles[i].addEventListener('click', e => this.handleToggleSidebar(e));
|
sidebarToggles[i].addEventListener('click', e => this.handleToggleSidebar(e));
|
||||||
}
|
|
||||||
|
|
||||||
this.newWikiForm = document.querySelector('form.new-wiki-page');
|
|
||||||
if (this.newWikiForm) {
|
|
||||||
this.newWikiForm.addEventListener('submit', e => this.handleNewWikiSubmit(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => this.renderSidebar());
|
|
||||||
this.renderSidebar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewWikiSubmit(e) {
|
this.newWikiForm = document.querySelector('form.new-wiki-page');
|
||||||
if (!this.newWikiForm) return;
|
if (this.newWikiForm) {
|
||||||
|
this.newWikiForm.addEventListener('submit', e => this.handleNewWikiSubmit(e));
|
||||||
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
|
|
||||||
const slug = gl.text.slugify(slugInput.value);
|
|
||||||
|
|
||||||
if (slug.length > 0) {
|
|
||||||
const wikisPath = slugInput.getAttribute('data-wikis-path');
|
|
||||||
window.location.href = `${wikisPath}/${slug}`;
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleSidebar(e) {
|
window.addEventListener('resize', () => this.renderSidebar());
|
||||||
|
this.renderSidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNewWikiSubmit(e) {
|
||||||
|
if (!this.newWikiForm) return;
|
||||||
|
|
||||||
|
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
|
||||||
|
const slug = gl.text.slugify(slugInput.value);
|
||||||
|
|
||||||
|
if (slug.length > 0) {
|
||||||
|
const wikisPath = slugInput.getAttribute('data-wikis-path');
|
||||||
|
window.location.href = `${wikisPath}/${slug}`;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.sidebarExpanded = !this.sidebarExpanded;
|
|
||||||
this.renderSidebar();
|
|
||||||
}
|
|
||||||
|
|
||||||
sidebarCanCollapse() {
|
|
||||||
const bootstrapBreakpoint = this.bp.getBreakpointSize();
|
|
||||||
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSidebar() {
|
|
||||||
if (!this.sidebarEl) return;
|
|
||||||
const { classList } = this.sidebarEl;
|
|
||||||
if (this.sidebarExpanded || !this.sidebarCanCollapse()) {
|
|
||||||
if (!classList.contains('right-sidebar-expanded')) {
|
|
||||||
classList.remove('right-sidebar-collapsed');
|
|
||||||
classList.add('right-sidebar-expanded');
|
|
||||||
}
|
|
||||||
} else if (classList.contains('right-sidebar-expanded')) {
|
|
||||||
classList.add('right-sidebar-collapsed');
|
|
||||||
classList.remove('right-sidebar-expanded');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Wikis = Wikis;
|
handleToggleSidebar(e) {
|
||||||
})(window.gl || (window.gl = {}));
|
e.preventDefault();
|
||||||
|
this.sidebarExpanded = !this.sidebarExpanded;
|
||||||
|
this.renderSidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
sidebarCanCollapse() {
|
||||||
|
const bootstrapBreakpoint = this.bp.getBreakpointSize();
|
||||||
|
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSidebar() {
|
||||||
|
if (!this.sidebarEl) return;
|
||||||
|
const { classList } = this.sidebarEl;
|
||||||
|
if (this.sidebarExpanded || !this.sidebarCanCollapse()) {
|
||||||
|
if (!classList.contains('right-sidebar-expanded')) {
|
||||||
|
classList.remove('right-sidebar-collapsed');
|
||||||
|
classList.add('right-sidebar-expanded');
|
||||||
|
}
|
||||||
|
} else if (classList.contains('right-sidebar-expanded')) {
|
||||||
|
classList.add('right-sidebar-collapsed');
|
||||||
|
classList.remove('right-sidebar-expanded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gl = window.gl || {};
|
||||||
|
window.gl.Wikis = Wikis;
|
||||||
|
|
|
@ -34,65 +34,64 @@ window.Dropzone = Dropzone;
|
||||||
// **Cancelable** No
|
// **Cancelable** No
|
||||||
// **Target** a.js-zen-leave
|
// **Target** a.js-zen-leave
|
||||||
//
|
//
|
||||||
(function() {
|
|
||||||
this.ZenMode = (function() {
|
|
||||||
function ZenMode() {
|
|
||||||
this.active_backdrop = null;
|
|
||||||
this.active_textarea = null;
|
|
||||||
$(document).on('click', '.js-zen-enter', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
return $(e.currentTarget).trigger('zen_mode:enter');
|
|
||||||
});
|
|
||||||
$(document).on('click', '.js-zen-leave', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
return $(e.currentTarget).trigger('zen_mode:leave');
|
|
||||||
});
|
|
||||||
$(document).on('zen_mode:enter', (function(_this) {
|
|
||||||
return function(e) {
|
|
||||||
return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop'));
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
$(document).on('zen_mode:leave', (function(_this) {
|
|
||||||
return function(e) {
|
|
||||||
return _this.exit();
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
$(document).on('keydown', function(e) {
|
|
||||||
// Esc
|
|
||||||
if (e.keyCode === 27) {
|
|
||||||
e.preventDefault();
|
|
||||||
return $(document).trigger('zen_mode:leave');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ZenMode.prototype.enter = function(backdrop) {
|
window.ZenMode = (function() {
|
||||||
Mousetrap.pause();
|
function ZenMode() {
|
||||||
this.active_backdrop = $(backdrop);
|
this.active_backdrop = null;
|
||||||
this.active_backdrop.addClass('fullscreen');
|
this.active_textarea = null;
|
||||||
this.active_textarea = this.active_backdrop.find('textarea');
|
$(document).on('click', '.js-zen-enter', function(e) {
|
||||||
// Prevent a user-resized textarea from persisting to fullscreen
|
e.preventDefault();
|
||||||
this.active_textarea.removeAttr('style');
|
return $(e.currentTarget).trigger('zen_mode:enter');
|
||||||
return this.active_textarea.focus();
|
});
|
||||||
};
|
$(document).on('click', '.js-zen-leave', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
ZenMode.prototype.exit = function() {
|
return $(e.currentTarget).trigger('zen_mode:leave');
|
||||||
if (this.active_textarea) {
|
});
|
||||||
Mousetrap.unpause();
|
$(document).on('zen_mode:enter', (function(_this) {
|
||||||
this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen');
|
return function(e) {
|
||||||
this.scrollTo(this.active_textarea);
|
return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop'));
|
||||||
this.active_textarea = null;
|
};
|
||||||
this.active_backdrop = null;
|
})(this));
|
||||||
return Dropzone.forElement('.div-dropzone').enable();
|
$(document).on('zen_mode:leave', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this.exit();
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
$(document).on('keydown', function(e) {
|
||||||
|
// Esc
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
e.preventDefault();
|
||||||
|
return $(document).trigger('zen_mode:leave');
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ZenMode.prototype.scrollTo = function(zen_area) {
|
ZenMode.prototype.enter = function(backdrop) {
|
||||||
return $.scrollTo(zen_area, 0, {
|
Mousetrap.pause();
|
||||||
offset: -150
|
this.active_backdrop = $(backdrop);
|
||||||
});
|
this.active_backdrop.addClass('fullscreen');
|
||||||
};
|
this.active_textarea = this.active_backdrop.find('textarea');
|
||||||
|
// Prevent a user-resized textarea from persisting to fullscreen
|
||||||
|
this.active_textarea.removeAttr('style');
|
||||||
|
return this.active_textarea.focus();
|
||||||
|
};
|
||||||
|
|
||||||
return ZenMode;
|
ZenMode.prototype.exit = function() {
|
||||||
})();
|
if (this.active_textarea) {
|
||||||
}).call(window);
|
Mousetrap.unpause();
|
||||||
|
this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen');
|
||||||
|
this.scrollTo(this.active_textarea);
|
||||||
|
this.active_textarea = null;
|
||||||
|
this.active_backdrop = null;
|
||||||
|
return Dropzone.forElement('.div-dropzone').enable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ZenMode.prototype.scrollTo = function(zen_area) {
|
||||||
|
return $.scrollTo(zen_area, 0, {
|
||||||
|
offset: -150
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return ZenMode;
|
||||||
|
})();
|
||||||
|
|
Loading…
Reference in a new issue