diff --git a/swh/web/assets/src/bundles/browse/browse-utils.js b/swh/web/assets/src/bundles/browse/browse-utils.js
index d7be7839..3cce9854 100644
--- a/swh/web/assets/src/bundles/browse/browse-utils.js
+++ b/swh/web/assets/src/bundles/browse/browse-utils.js
@@ -1,70 +1,72 @@
/**
* Copyright (C) 2018 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
+import {BREAKPOINT_SM} from 'utils/constants';
+
$(document).ready(() => {
$('.dropdown-submenu a.dropdown-item').on('click', e => {
$(e.target).next('div').toggle();
if ($(e.target).next('div').css('display') !== 'none') {
$(e.target).focus();
} else {
$(e.target).blur();
}
e.stopPropagation();
e.preventDefault();
});
$('.swh-popover-toggler').popover({
boundary: 'viewport',
container: 'body',
html: true,
placement: function() {
const width = $(window).width();
- if (width < 768) {
+ if (width < BREAKPOINT_SM) {
return 'top';
} else {
return 'right';
}
},
template: `
`,
content: function() {
var content = $(this).attr('data-popover-content');
return $(content).children('.popover-body').remove().html();
},
title: function() {
var title = $(this).attr('data-popover-content');
return $(title).children('.popover-heading').html();
},
offset: '50vh',
sanitize: false
});
$('.swh-vault-menu a.dropdown-item').on('click', e => {
$('.swh-popover-toggler').popover('hide');
});
$('.swh-popover-toggler').on('show.bs.popover', (e) => {
$(`.swh-popover-toggler:not(#${e.currentTarget.id})`).popover('hide');
$('.swh-vault-menu .dropdown-menu').hide();
});
$('.swh-actions-dropdown').on('hide.bs.dropdown', () => {
$('.swh-vault-menu .dropdown-menu').hide();
$('.swh-popover-toggler').popover('hide');
});
$('body').on('click', e => {
if ($(e.target).parents('.swh-popover').length) {
e.stopPropagation();
}
});
});
diff --git a/swh/web/assets/src/bundles/webapp/webapp-utils.js b/swh/web/assets/src/bundles/webapp/webapp-utils.js
index 50f2d5ed..340d9d3b 100644
--- a/swh/web/assets/src/bundles/webapp/webapp-utils.js
+++ b/swh/web/assets/src/bundles/webapp/webapp-utils.js
@@ -1,207 +1,213 @@
import objectFitImages from 'object-fit-images';
import {Layout} from 'admin-lte';
import {selectText} from 'utils/functions';
+import {BREAKPOINT_MD} from 'utils/constants';
let collapseSidebar = false;
let previousSidebarState = localStorage.getItem('swh-sidebar-collapsed');
if (previousSidebarState !== undefined) {
collapseSidebar = JSON.parse(previousSidebarState);
}
// adapt implementation of fixLayoutHeight from admin-lte
Layout.prototype.fixLayoutHeight = () => {
let heights = {
window: $(window).height(),
header: $('.main-header').outerHeight(),
footer: $('.footer').outerHeight(),
sidebar: $('.main-sidebar').height(),
topbar: $('.swh-top-bar').height()
};
let offset = 10;
$('.content-wrapper').css('min-height', heights.window - heights.topbar - heights.header - heights.footer - offset);
$('.main-sidebar').css('min-height', heights.window - heights.topbar - heights.header - heights.footer - offset);
};
$(document).on('DOMContentLoaded', () => {
+ // set state to collapsed on smaller devices
+ if ($(window).width() < BREAKPOINT_MD) {
+ collapseSidebar = true;
+ }
+
// restore previous sidebar state (collapsed/expanded)
if (collapseSidebar) {
// hack to avoid animated transition for collapsing sidebar
// when loading a page
let sidebarTransition = $('.main-sidebar, .main-sidebar:before').css('transition');
let sidebarEltsTransition = $('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition');
$('.main-sidebar, .main-sidebar:before').css('transition', 'none');
$('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition', 'none');
$('body').addClass('sidebar-collapse');
$('.swh-words-logo-swh').css('visibility', 'visible');
// restore transitions for user navigation
setTimeout(() => {
$('.main-sidebar, .main-sidebar:before').css('transition', sidebarTransition);
$('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition', sidebarEltsTransition);
});
}
});
$(document).on('collapsed.lte.pushmenu', event => {
- if ($('body').width() > 980) {
+ if ($('body').width() >= BREAKPOINT_MD) {
$('.swh-words-logo-swh').css('visibility', 'visible');
}
});
$(document).on('shown.lte.pushmenu', event => {
$('.swh-words-logo-swh').css('visibility', 'hidden');
});
function ensureNoFooterOverflow() {
$('body').css('padding-bottom', $('footer').outerHeight() + 'px');
}
$(document).ready(() => {
// redirect to last browse page if any when clicking on the 'Browse' entry
// in the sidebar
$(`.swh-browse-link`).click(event => {
let lastBrowsePage = sessionStorage.getItem('last-browse-page');
if (lastBrowsePage) {
event.preventDefault();
window.location = lastBrowsePage;
}
});
// ensure footer do not overflow main content for mobile devices
// or after resizing the browser window
ensureNoFooterOverflow();
$(window).resize(function() {
ensureNoFooterOverflow();
- if ($('body').hasClass('sidebar-collapse') && $('body').width() > 980) {
+ if ($('body').hasClass('sidebar-collapse') && $('body').width() >= BREAKPOINT_MD) {
$('.swh-words-logo-swh').css('visibility', 'visible');
}
});
// activate css polyfill 'object-fit: contain' in old browsers
objectFitImages();
// reparent the modals to the top navigation div in order to be able
// to display them
$('.swh-browse-top-navigation').append($('.modal'));
let selectedCode = null;
function getCodeOrPreEltUnderPointer(e) {
let elts = document.elementsFromPoint(e.clientX, e.clientY);
for (let elt of elts) {
if (elt.nodeName === 'CODE' || elt.nodeName === 'PRE') {
return elt;
}
}
return null;
}
// click handler to set focus on code block for copy
$(document).click(e => {
selectedCode = getCodeOrPreEltUnderPointer(e);
});
function selectCode(event, selectedCode) {
if (selectedCode) {
let hljsLnCodeElts = $(selectedCode).find('.hljs-ln-code');
if (hljsLnCodeElts.length) {
selectText(hljsLnCodeElts[0], hljsLnCodeElts[hljsLnCodeElts.length - 1]);
} else {
selectText(selectedCode.firstChild, selectedCode.lastChild);
}
event.preventDefault();
}
}
// select the whole text of focused code block when user
// double clicks or hits Ctrl+A
$(document).dblclick(e => {
if ((e.ctrlKey || e.metaKey)) {
selectCode(e, getCodeOrPreEltUnderPointer(e));
}
});
$(document).keydown(e => {
if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
selectCode(e, selectedCode);
}
});
// show/hide back-to-top button
let scrollThreshold = 0;
scrollThreshold += $('.swh-top-bar').height() || 0;
scrollThreshold += $('.navbar').height() || 0;
$(window).scroll(() => {
if ($(window).scrollTop() > scrollThreshold) {
$('#back-to-top').css('display', 'block');
} else {
$('#back-to-top').css('display', 'none');
}
});
});
export function initPage(page) {
$(document).ready(() => {
// set relevant sidebar link to page active
$(`.swh-${page}-item`).addClass('active');
$(`.swh-${page}-link`).addClass('active');
// triggered when unloading the current page
$(window).on('unload', () => {
// backup sidebar state (collapsed/expanded)
let sidebarCollapsed = $('body').hasClass('sidebar-collapse');
localStorage.setItem('swh-sidebar-collapsed', JSON.stringify(sidebarCollapsed));
// backup current browse page
if (page === 'browse') {
sessionStorage.setItem('last-browse-page', window.location);
}
});
});
}
export function showModalMessage(title, message) {
$('#swh-web-modal-message .modal-title').text(title);
$('#swh-web-modal-message .modal-content p').text(message);
$('#swh-web-modal-message').modal('show');
}
export function showModalConfirm(title, message, callback) {
$('#swh-web-modal-confirm .modal-title').text(title);
$('#swh-web-modal-confirm .modal-content p').text(message);
$('#swh-web-modal-confirm #swh-web-modal-confirm-ok-btn').bind('click', () => {
callback();
$('#swh-web-modal-confirm').modal('hide');
$('#swh-web-modal-confirm #swh-web-modal-confirm-ok-btn').unbind('click');
});
$('#swh-web-modal-confirm').modal('show');
}
let swhObjectIcons;
export function setSwhObjectIcons(icons) {
swhObjectIcons = icons;
}
export function getSwhObjectIcon(swhObjectType) {
return swhObjectIcons[swhObjectType];
}
let reCaptchaActivated;
export function setReCaptchaActivated(activated) {
reCaptchaActivated = activated;
}
export function isReCaptchaActivated() {
return reCaptchaActivated;
}
let browsedSwhObjectMetadata = {};
export function setBrowsedSwhObjectMetadata(metadata) {
browsedSwhObjectMetadata = metadata;
}
export function getBrowsedSwhObjectMetadata() {
return browsedSwhObjectMetadata;
}
diff --git a/swh/web/assets/src/utils/constants.js b/swh/web/assets/src/utils/constants.js
new file mode 100644
index 00000000..166e1dc1
--- /dev/null
+++ b/swh/web/assets/src/utils/constants.js
@@ -0,0 +1,4 @@
+// Constants defining Bootstrap Breakpoints
+export const BREAKPOINT_SM = 768;
+export const BREAKPOINT_MD = 992;
+export const BREAKPOINT_LG = 1200;